0%

IO流-2

IO流

FileCopy

  • 字节节点流拷贝文件(FileInputStream + FileOutputStream):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.f.chapter19.outputstream_;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* @author fzy
* @date 2023/7/10 20:57
* 使用FileInputStream和FileOutputStream对文件进行复制
*/
public class FileCopy {
public static void main(String[] args) {
String srcFilePath = "C:\\Users\\1\\Doc\\入党相关\\会议背景.jpg";
String destFilePath = "C:\\Users\\1\\Doc\\入党相关\\会议背景-copy.jpg";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
int readLen = 0;
byte[] buf = new byte[1024]; //读取缓冲区
try {
if (new File(srcFilePath).exists()) {
fileInputStream = new FileInputStream(srcFilePath); //文件输入流
} else {
System.out.println("要复制的文件不存在!");
return;
}
fileOutputStream = new FileOutputStream(destFilePath); //文件输出流
while ((readLen = fileInputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, readLen);
}
System.out.println("文件复制成功!");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileInputStream.close();
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
  • 字节处理流拷贝文件(BufferedInputStream + BufferedOutputStream):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.f.chapter19.outputstream_;

import java.io.*;

/**
* @author fzy
* @date 2023/7/11 16:18
* 使用BufferedInputStream和BufferedOutputStream对文件进行复制
*/
public class FileCopy02 {
public static void main(String[] args) {
String srcFilePath = "C:\\Users\\1\\Doc\\入党相关\\会议背景.jpg";
String destFilePath = "C:\\Users\\1\\Doc\\入党相关\\会议背景-copy.jpg";
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
byte[] buf = new byte[1024];
int readLen = 0;

try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFilePath));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFilePath));

while ((readLen = bufferedInputStream.read(buf)) != -1) {
bufferedOutputStream.write(buf, 0, readLen);
}

System.out.println("拷贝成功!");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
bufferedInputStream.close();
bufferedOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

Reader

  • Reader 抽象类是所有字符输入流的父类:public abstract class Reader implements Readable, Closeable

  • Reader 的常用子类:

    • FileReader:文件字符输入流。
    • BufferedReader:缓冲字符输入流。
    • InputStreamReader:转换输入流。
FileReader
  • public class FileReader extends InputStreamReader
  1. public int read() :每次读取单个字符,返回该字符,如果到文件末尾返回 -1

  2. public int read(char cbuf[], int offset, int length):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾则返回 -1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.f.chapter19.reader_;

    import java.io.FileReader;
    import java.io.IOException;

    /**
    * @author fzy
    * @date 2023/7/10 20:18
    * 演示FileReader的使用(字符输入流:文件 --> 程序)
    */
    public class FileReader_ {
    public static void main(String[] args) {
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\file\\hello.txt";
    FileReader fileReader = null;
    char[] buf = new char[8];
    int readLen = 0;
    try {
    fileReader = new FileReader(filePath);
    while ((readLen = fileReader.read(buf)) != -1) {
    System.out.println(new String(buf, 0, readLen));
    }
    } catch (IOException e) {
    throw new RuntimeException(e);
    } finally {
    try {
    fileReader.close();
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    }
    }
    }
BufferedReader
  • public class BufferedReader extends Reader

  • 使用 BufferedReader 读取文本文件,并显示在控制台。

    将节点流作为参数传入处理流的构造器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package com.f.chapter19.reader_;

    import java.io.BufferedReader;
    import java.io.FileReader;

    /**
    * @author fzy
    * @date 2023/7/11 15:26
    * 使用 `BufferedReader` 读取文本文件,并显示在控制台。
    */
    public class BufferedReader_ {
    public static void main(String[] args) throws Exception {
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\javaedu\\src\\com\\f\\chapter10\\TestMainParam.java";
    BufferedReader bufferedReader = null;
    bufferedReader = new BufferedReader(new FileReader(filePath));
    String line = null;
    int cnt = 1;
    //bufferedReader.readLine() 是按行读取文件。当返回 null 时,表示文件读取完毕。
    while ((line = bufferedReader.readLine()) != null) {
    System.out.print("读取第" + (cnt++) + "行:");
    System.out.println(line);
    }

    //不要忘记关闭流。只需要关闭外层流即可,因为底层会去自动关闭节点流
    bufferedReader.close();
    }
    }
InputStreamReader
  • public class InputStreamReader extends Reader

  • 字节流 FilelnputStream 包装成(转换成)字符流 InputStreamReader,对文件进行读取(按照 gbk 格式),进而再包装成 BufferedReader

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    package com.f.chapter19.transformation_;

    import java.io.*;

    /**
    * @author fzy
    * @date 2023/7/12 15:55
    */
    public class InputStreamReader_ {
    public static void main(String[] args) {
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\file\\note.txt";
    InputStreamReader inputStreamReader = null;
    BufferedReader bufferedReader = null;
    String line = null;
    try {
    //将 FileInputStream(字节流) 包装成 InputStreamReader(字符流),并指定了编码为 gbk
    inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "gbk");
    //把 InputStreamReader 传入 BufferedReader,以提高效率
    bufferedReader = new BufferedReader(inputStreamReader);
    ////更简略的写法
    //bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "gbk"));
    while ((line = bufferedReader.readLine()) != null) {
    System.out.println(line);
    }
    } catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e);
    } catch (IOException e) {
    throw new RuntimeException(e);
    } finally {
    try {
    bufferedReader.close(); //关闭最外层的流即可
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    }
    }
    }

Writer

  • Writer 抽象类是所有字符输出流的父类:public abstract class Writer implements Appendable, Closeable, Flushable

  • Writer 的常用子类:

    • FileWriter:文件字符输出流。
    • BufferedWriter:缓冲字符输出流。
    • OutputStreamWriter:转换输出流。
FileWriter
  • public class FileWriter extends OutputStreamWriter
  1. public void write(int c):将指定的字符写入文件,如果文件不存在,则创建该文件,下面的方法同理。

  2. public void write(char cbuf[]):将 cbuf.length 个字符从指定的字符数组写入文件。

  3. public void write(char cbuf[], int off, int len):将 len 个字节从位于偏移量 off 的指定字符数组写入此文件。

  4. public void write(String str):写入整个字符串。

  5. public void write(String str, int off, int len):写入字符串的指定部分。

    注意FileWriter 使用后,必须要关闭(close刷新(flush,否则写入不到指定的文件。因为在调用了 fileWriter.flush(); 或者 fileWriter.close(); 后,最终会调用 OutputStreamwrite 方法,该方法才真正将内容写入文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //OutputStream的write方法
    public void write(byte b[], int off, int len) throws IOException {
    if (b == null) {
    throw new NullPointerException();
    } else if ((off < 0) || (off > b.length) || (len < 0) ||
    ((off + len) > b.length) || ((off + len) < 0)) {
    throw new IndexOutOfBoundsException();
    } else if (len == 0) {
    return;
    }
    for (int i = 0 ; i < len ; i++) {
    write(b[off + i]);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package com.f.chapter19.writer_;

    import java.io.FileWriter;
    import java.io.IOException;

    /**
    * @author fzy
    * @date 2023/7/10 21:09
    */
    public class FileWriter_ {
    public static void main(String[] args) {
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\file\\note.txt";
    FileWriter fileWriter = null;
    char[] chars = {'h', 'd', 'l', 'g', 'd', 'x', '\n'};
    try {
    fileWriter = new FileWriter(filePath, true); //append置为true,表示追加
    fileWriter.write('F'); //写入单个字符
    fileWriter.write('\n'); //换行
    fileWriter.write(chars); //写入字符数组
    fileWriter.write(chars, 0, chars.length);
    fileWriter.write("写入这一行\n"); //写入字符串
    fileWriter.write("写入这一行的一部分", 0, 3); //将 “写入这” 写入了文件
    } catch (IOException e) {
    throw new RuntimeException(e);
    } finally {
    try {
    fileWriter.close(); //必须要关闭(`close`)或刷新(`flush`),否则写入不到指定的文件。
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    System.out.println("程序结束...");
    }
    }
    }
BufferedWriter
  • public class BufferedWriter extends Writer

  • 使用 BufferedWriter 将文本写入到文件中。

    将节点流作为参数传入处理流的构造器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.f.chapter19.writer_;

    import java.io.BufferedWriter;
    import java.io.FileWriter;

    /**
    * @author fzy
    * @date 2023/7/11 15:49
    */
    public class BufferedWriter_ {
    public static void main(String[] args) throws Exception {
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\file\\note.txt";
    BufferedWriter bufferedWriter = null;
    bufferedWriter = new BufferedWriter(new FileWriter(filePath, true)); //append置为true表示追加
    bufferedWriter.write("向文件中写入这一行...");
    //写一行行分隔符。 行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符('\n')字符。
    bufferedWriter.newLine();
    System.out.println("写入成功!");
    bufferedWriter.close(); //关闭流
    }
    }
OutputStreamWriter
  • public class OutputStreamWriter extends Writer

  • 字节流 FileOutputStream 包装成(转换成)字符流 OutputStreamWriter,对文件进行写入(按照 gbk 格式,也可以指定其他,比如 utf-8)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package com.f.chapter19.transformation_;

    import java.io.*;

    /**
    * @author fzy
    * @date 2023/7/12 16:21
    */
    public class OutputStreamWriter_ {
    public static void main(String[] args) {
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\file\\note.txt";
    OutputStreamWriter outputStreamWriter = null;
    String charSet = "gbk";
    try {
    outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
    outputStreamWriter.write("你好!");
    } catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e);
    } catch (IOException e) {
    throw new RuntimeException(e);
    } finally {
    try {
    outputStreamWriter.close();
    System.out.println("按照 " + charSet + " 编码方式保存文件成功!");
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    }
    }
    }
PrintWriter
  • public class PrintWriter extends Writer
  • 字符打印流

★序列化和反序列化

  • 看下面两个需求:

    • int num=100 这个 int 数据保存到文件中,注意不是 100 数字,而是 int 100,并且能够从文件中直接恢复 int 100
    • Dog dog=new Dog(“小黄”, 3) 这个 dog 对像保存到文件中,并且能够从文件恢复。

    上面的要求,就是能够将基本数据类型或者对象进行序列化和反序列化的操作。

  • 序列化和反序列化:

    1. 序列化就是在保存数据时,保存数据的值和数据类型
    2. 反序列化就是在恢复数据时,恢复数据的值和数据类型
    3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一
      • Serializable //这是一个标记接口,没有方法 -> 优先使用
      • Externalizable //该接口有方法需要实现,一般使用 Serializable 接口
  • 为了表示目录中 InputStream、OutputStream、Reader、Writer 及其子类的关系,所以 ObjectInputStreamObjectOutputStream 仍然放在 InputStreamOutputStream 的目录下面。

    • ObjectOutputStream 提供序列化的功能。
    • ObjectInputStream 提供反序列化的功能。
★对象处理流的使用细节
  1. 读写顺序要一致
  2. 要求序列化或反序列化的对象,其对应的类需要实现 SerializableExternalizable 接口
  3. 序列化的类中建议添加 private static final long SerialVersionUID,为了提高版本的兼容性。
  4. 序列化对象时,默认将里面所有属性都进行序列化,但除了 statictransient 修饰的成员,即不会将这两种成员序列化保存到文件中
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化。

标准输入输出流

类型默认设备
System.in 标准输入InputStream键盘
System.out 标准输出PrintStream显示器
  • System.in 的编译类型是 InputStream,运行类型是 BufferedInputStream
    • System 类中:public final static InputStream in = null;
  • System.out 的编译类型是 PrintStream,运行类型是 PrintStream
    • System 类中:public final static PrintStream out = null;

转换流

  • 转换流是将字节流包装为字符流

  • InputStreamReaderOutputStreamWriter

    1. InputStreamReaderReader 的子类,可以将 InputStream(字节流)包装成 Reader(字符流)。
    2. OutputStreamWriterWriter 的子类,实现将 OutputStream(字节流)包装成Writer(字符流)。
    3. 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
    4. 可以在使用时指定编码格式(比如 utf-8gbkgb2312ISO8859-1 等)。
  • 为了表示目录中 InputStream、OutputStream、Reader、Writer 及其子类的关系,所以 InputStreamReaderOutputStreamWriter 仍然放在 ReaderWriter 的目录下面。

打印流

  • PrintStream 字节打印流和 PrintWriter 字符打印流。

    打印流只有输出流,没有输入流。

  • 为了表示目录中 InputStream、OutputStream、Reader、Writer 及其子类的关系,所以 PrintStreamPrintWriter 仍然放在 OutputStreamWriter 的目录下面。

★Properties

  • 接着“第十四章 集合”中,Properties 的话题。

  • Properties专门用于读写配置文件的集合类。

    1
    2
    3
    4
    //配置文件的格式
    键=值
    键=值
    ...

    **注意:键值对不需要有空格,值不需要用引号引起来,默认类型是 String**。

  • Properties 的常见方法:

    1. public synchronized void load(Reader reader)public synchronized void load(InputStream inStream)加载配置文件的键值对到 Properties 对象。
    2. public void list(PrintStream out):将数据显示到指定设备 / 流对象。
    3. getProperty(key):根据键获取值。
    4. setProperty(key, value):设置键值对到 Properties 对象。-> 若 key 存在则修改,不存在则添加。
    5. public void store(Writer writer, String comments)Properties 中的键值对存储到配置文件,在 idea 中,保存信息到配置文件,如果含有中文,会存储为 unicode 码。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package com.f.chapter19.properties_;

    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Properties;

    /**
    * @author fzy
    * @date 2023/7/12 20:03
    */
    public class Properties_ {
    public static void main(String[] args) {
    //使用 Properties 类来读取 mysql.peoperties 文件
    String filePath = "C:\\Users\\1\\Code Project\\Java project\\file\\mysql.properties";
    Properties properties = new Properties();
    try {
    //1.`load`:加载配置文件的键值对到 `Properties` 对象。
    properties.load(new FileReader(filePath));
    //2.`list`:将数据显示到指定设备 / 流对象。
    properties.list(System.out);
    //3.`getProperty(key)`:根据键获取值。
    System.out.println("用户名 = " + properties.getProperty("user"));
    System.out.println("密码 = " + properties.getProperty("pwd"));
    //4.`setProperty(key, value)`:设置键值对到 `Properties` 对象。
    properties.setProperty("charset", "utf-8");
    //5.`store`:将 `Properties` 中的键值对存储到配置文件,在 `idea` 中,保存信息到配置文件,如果含有中文,会存储为 `unicode` 码。
    properties.store(new FileWriter(filePath), "This is a comment.");
    System.out.println("保存配置文件成功!");
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    }
    }
---------------The End---------------