前言
Java通过I/O流实现文件读写学习笔记
继承结构
graph TD
Object --> InputStream
InputStream --> FileInputStream
Object --> OutputStream
OutputStream --> FileOutputStream
Object --> Reader
Reader --> InputStreamReader
InputStreamReader --> FileReader
Object --> Writer
Writer --> OutputStreamWriter
OutputStreamWriter --> FileWriter
InputStream --> BufferedInputStream
OutputStream --> BufferedOutputStream
Reader --> BufferedReader
Writer --> BufferedWriter
AutoCloseable --> Closeable
Closeable --> InputStream
Closeable --> OutputStream
Flushable --> OutputStream
Readable --> Reader
Closeable --> Reader
Appendable --> Writer
Closeable --> Writer
Flushable --> Writer
style Object fill:#f0f8ff,stroke:#696969
style InputStream fill:#f0f8ff,stroke:#696969
style FileInputStream fill:#f0f8ff,stroke:#696969
style OutputStream fill:#f0f8ff,stroke:#696969
style FileOutputStream fill:#f0f8ff,stroke:#696969
style Reader fill:#f0f8ff,stroke:#696969
style InputStreamReader fill:#f0f8ff,stroke:#696969
style FileReader fill:#f0f8ff,stroke:#696969
style Writer fill:#f0f8ff,stroke:#696969
style OutputStreamWriter fill:#f0f8ff,stroke:#696969
style FileWriter fill:#f0f8ff,stroke:#696969
style BufferedInputStream fill:#f0f8ff,stroke:#696969
style BufferedOutputStream fill:#f0f8ff,stroke:#696969
style BufferedReader fill:#f0f8ff,stroke:#696969
style BufferedWriter fill:#f0f8ff,stroke:#696969
style AutoCloseable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
style Readable fill:#f0f8ff,stroke:#4169e1
style Appendable fill:#f0f8ff,stroke:#4169e1
文件字节流
继承结构
graph TD
Object --> InputStream
InputStream --> FileInputStream
Object --> OutputStream
OutputStream --> FileOutputStream
AutoCloseable --> Closeable
Closeable --> InputStream
Closeable --> OutputStream
Flushable --> OutputStream
style Object fill:#f0f8ff,stroke:#696969
style InputStream fill:#f0f8ff,stroke:#696969
style FileInputStream fill:#f0f8ff,stroke:#696969
style OutputStream fill:#f0f8ff,stroke:#696969
style FileOutputStream fill:#f0f8ff,stroke:#696969
style AutoCloseable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
<file>:文件路径
1 2 3 4 5
| FileInputStream fileInputStream = new FileInputStream("<file>");
...
fileInputStream.close();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream("<file>");
...
} catch (IOException e) { e.printStackTrace(); } finally { if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
- 通过Java7的try-with-resources(自动资源管理)来自动释放资源
只要实现了AutoCloseable接口的类,就可以通过try-with-resources来创建对象
1 2 3 4 5
| try (FileInputStream fileInputStream = new FileInputStream("<file>")) { ... } catch (IOException e) { e.printStackTrace(); }
|
读取字节
读取一个字节数据
1 2
| int b = fileInputStream.read(); char c = (char) b;
|
读取字节数组
1 2 3 4 5
| byte[] buffer = new byte[1024]; int length = fileInputStream.read(buffer); for (int i = 0; i < length; i++) { char c = (char) buffer[i]; }
|
读取指定长度的字节数据
0:从buffer的哪个索引存储数据
1024:读取的长度是多少
1 2 3 4 5
| byte[] buffer = new byte[1024]; int length = fileInputStream.read(buffer, 0, 1024); for (int i = 0; i < length; i++) { char c = (char) buffer[i]; }
|
跳过指定长度的字节数据
1
| fileInputStream.skip(1024);
|
输出流
创建对象
false:是否是追加写入,缺省值为false表示从文件头覆盖写入,为true表示从文件尾追加写入
1 2 3 4 5
| try (FileInputStream fileInputStream = new FileInputStream("<file>"), false) { ... } catch (IOException e) { e.printStackTrace(); }
|
写入字节
写入一个字节数据
1 2
| byte b = ''; fileInputStream.write(b);
|
写入字节数组
1 2
| byte[] buffer = "".getBytes(); fileInputStream.write(buffer);
|
写入指定长度的字节数据
0:从buffer的哪个索引开始写入数据
buffer.length:写入的长度是多少
1 2
| byte[] buffer = "".getBytes(); fileInputStream.write(buffer, 0, buffer.length);
|
指定字符集
1 2
| byte[] buffer = "".getBytes("UTF-8"); fileInputStream.write(buffer);
|
强制刷新缓存
- Java内部有缓存机制,每次指定写入数据并不会立即写入到文件,而是缓存满了才会执行文件的写入
- 通过
flush()方法可以强制刷新缓存,立即将缓存的所有数据写入到文件
1
| fileInputStream.flush();
|
同时创建输入流和输出流对象并捕获异常
1 2 3 4 5
| try (FileInputStream fileInputStream = new FileInputStream("<file>"); FileOutputStream fileOutputStream = new FileOutputStream("<file>")) { ... } catch (IOException e) { e.printStackTrace(); }
|
文件字符流
继承结构
graph TD
Object --> Reader
Reader --> InputStreamReader
InputStreamReader --> FileReader
Object --> Writer
Writer --> OutputStreamWriter
OutputStreamWriter --> FileWriter
Readable --> Reader
Closeable --> Reader
Appendable --> Writer
Closeable --> Writer
Flushable --> Writer
style Object fill:#f0f8ff,stroke:#696969
style Reader fill:#f0f8ff,stroke:#696969
style InputStreamReader fill:#f0f8ff,stroke:#696969
style FileReader fill:#f0f8ff,stroke:#696969
style Writer fill:#f0f8ff,stroke:#696969
style OutputStreamWriter fill:#f0f8ff,stroke:#696969
style FileWriter fill:#f0f8ff,stroke:#696969
style Readable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Appendable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
1 2 3 4 5
| try (FileReader fileReader = new FileReader("<file>")) { ... } catch (IOException e) { e.printStackTrace(); }
|
读取字符
读取一个字符数据
1 2
| int b = fileReader.read(); char c = (char) b;
|
读取字符数组
1 2 3 4 5
| char[] cs = new char[1024]; int length = fileReader.read(cs); for (int i = 0; i < length; i++) { char c = cs[i]; }
|
转换为字符串
1 2 3
| char[] cs = new char[1024]; fileReader.read(cs); String s = new String(cs);
|
跳过指定字符的数据
输出流
创建对象
false:是否是追加写入,缺省值为false表示从文件头覆盖写入,为true表示从文件尾追加写入
1 2 3
| try (FileWriter fileWriter = new FileWriter("<file>", false)) { ... }
|
写入字符
写入一个字符
1 2
| char c = ''; fileWriter.write(c);
|
写入字符数组
1 2
| char[] cs = "".toCharArray(); fileWriter.write(cs);
|
写入字符串
1 2
| String s = ""; fileWriter.write(s);
|
追加写入字符
append()方法返回FileWriter对象,可以链式调用
1 2 3 4
| String c = ''; String cs = "".toCharArray(); String s = ""; fileWriter.append(c).append(cs).append(s);
|
强制刷新缓存
获取字符编码
1
| String encoding = fileWriter.getEncoding();
|
带缓冲区的字节流
继承结构
graph TD
Object --> InputStream
InputStream --> BufferedInputStream
Object --> OutputStream
OutputStream --> BufferedOutputStream
AutoCloseable --> Closeable
Closeable --> InputStream
Closeable --> OutputStream
Flushable --> OutputStream
style Object fill:#f0f8ff,stroke:#696969
style InputStream fill:#f0f8ff,stroke:#696969
style BufferedInputStream fill:#f0f8ff,stroke:#696969
style OutputStream fill:#f0f8ff,stroke:#696969
style BufferedOutputStream fill:#f0f8ff,stroke:#696969
style AutoCloseable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
1 2 3 4 5
| try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
手动指定缓冲区大小
1 2 3 4 5
| try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("<file>"), 1024)) { ... } catch (IOException e) { e.printStackTrace(); }
|
读取字节
传送门
重新读取
标记
0:标记接下来读取几次之内可以回溯,这个数只有大于缓冲区大小才会生效,如果这个数小于等于缓冲区大小,这个数实际上都会与缓冲区大小保持一致
1
| bufferedInputStream.mark(0);
|
回溯
- 在回溯之前必须先标记
- 如果读取次数超过标记次数之后进行回溯会报错
1
| bufferedInputStream.reset();
|
输出流
创建对象
1 2 3 4 5
| try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
手动指定缓冲区大小
1 2 3 4 5
| try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("<file>"), 1024)) { ... } catch (IOException e) { e.printStackTrace(); }
|
写入字节
传送门
带缓冲区的字符流
继承结构
graph TD
Object --> Reader
Reader --> BufferedReader
Object --> Writer
Writer --> BufferedWriter
Readable --> Reader
Closeable --> Reader
Appendable --> Writer
Closeable --> Writer
Flushable --> Writer
style Object fill:#f0f8ff,stroke:#696969
style Reader fill:#f0f8ff,stroke:#696969
style BufferedReader fill:#f0f8ff,stroke:#696969
style Writer fill:#f0f8ff,stroke:#696969
style BufferedWriter fill:#f0f8ff,stroke:#696969
style Readable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Appendable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
1 2 3 4 5
| try (BufferedReader bufferedReader = new BufferedReader(new FileReader("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
手动指定缓冲区大小
1 2 3 4 5
| try (BufferedReader bufferedReader = new BufferedReader(new FileReader("<file>"), 1024)) { ... } catch (IOException e) { e.printStackTrace(); }
|
读取字符
传送门
读取一行字符数据
1
| String line = bufferedReader.readLine();
|
判断是否支持标记
1
| boolean ok = bufferedReader.markSupported();
|
输出流
创建对象
1 2 3 4 5
| try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
手动指定缓冲区大小
1 2 3 4 5
| try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("<file>"), 1024)) { ... } catch (IOException e) { e.printStackTrace(); }
|
写入字符
传送门
写入换行符
1
| bufferedWriter.newLine();
|
转换流
文件字节流转换为文件字符流
继承结构
graph TD
Object --> Reader
Reader --> InputStreamReader
Object --> Writer
Writer --> OutputStreamWriter
Readable --> Reader
Closeable --> Reader
Appendable --> Writer
Closeable --> Writer
Flushable --> Writer
style Object fill:#f0f8ff,stroke:#696969
style Reader fill:#f0f8ff,stroke:#696969
style InputStreamReader fill:#f0f8ff,stroke:#696969
style Writer fill:#f0f8ff,stroke:#696969
style OutputStreamWriter fill:#f0f8ff,stroke:#696969
style Readable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Appendable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
1 2 3 4 5
| try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
输出流
创建对象
1 2 3 4 5
| try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
打印流
继承结构
graph TD
Object --> Reader
Reader --> InputStreamReader
Object --> Writer
Writer --> OutputStreamWriter
Readable --> Reader
Closeable --> Reader
Appendable --> Writer
Closeable --> Writer
Flushable --> Writer
style Object fill:#f0f8ff,stroke:#696969
style Reader fill:#f0f8ff,stroke:#696969
style InputStreamReader fill:#f0f8ff,stroke:#696969
style Writer fill:#f0f8ff,stroke:#696969
style OutputStreamWriter fill:#f0f8ff,stroke:#696969
style Readable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Appendable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输出流
创建对象
1 2 3 4 5
| try (PrintStream printStream = new PrintStream(new FileOutputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
打印字符串
1 2
| String s = ""; printStream.print(s);
|
打印末尾换行的字符串
1 2
| String s = ""; printStream.println(s);
|
打印包含格式说明符的字符串
传送门
1 2
| String s = "%s"; printStream.printf(s, "");
|
数据流
继承结构
graph TD
Object --> InputStream
InputStream --> FilterInputStream
FilterInputStream --> DataInputStream
Object --> OutputStream
OutputStream --> FilterOutputStream
FilterOutputStream --> DataOutputStream
AutoCloseable --> Closeable
Closeable --> InputStream
Closeable --> OutputStream
Flushable --> OutputStream
DataInput --> DataInputStream
DataOutput --> DataOutputStream
style Object fill:#f0f8ff,stroke:#696969
style InputStream fill:#f0f8ff,stroke:#696969
style FilterInputStream fill:#f0f8ff,stroke:#696969
style DataInputStream fill:#f0f8ff,stroke:#696969
style OutputStream fill:#f0f8ff,stroke:#696969
style FilterOutputStream fill:#f0f8ff,stroke:#696969
style DataOutputStream fill:#f0f8ff,stroke:#696969
style AutoCloseable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
style DataInput fill:#f0f8ff,stroke:#4169e1
style DataOutput fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
1 2 3 4 5
| try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
读取数据
1
| byte result = dataInputStream.readByte();
|
1
| short result = dataInputStream.readShort();
|
1
| int result = dataInputStream.readInt();
|
1
| long result = dataInputStream.readLong();
|
1
| double result = dataInputStream.readDouble();
|
1
| float result = dataInputStream.readFloat();
|
1
| boolean result = dataInputStream.readBoolean();
|
1
| char result = dataInputStream.readChar();
|
输出流
创建对象
1 2 3 4 5
| try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); }
|
写入数据
1
| dataOutputStream.writeByte(0);
|
1
| dataOutputStream.writeShort(0);
|
1
| dataOutputStream.writeInt(0);
|
1
| dataOutputStream.writeLong(0);
|
1
| dataOutputStream.writeDouble(0);
|
1
| dataOutputStream.writeFloat(0);
|
1
| dataOutputStream.writeBoolean(false);
|
1
| dataOutputStream.writeChar(' ');
|
对象流
继承结构
graph TD
Object --> InputStream
InputStream --> ObjectInputStream
Object --> OutputStream
OutputStream --> ObjectOutputStream
AutoCloseable --> Closeable
Closeable --> InputStream
Closeable --> OutputStream
Flushable --> OutputStream
DataInput --> ObjectInput
AutoCloseable --> ObjectInput
ObjectInput --> ObjectInputStream
ObjectStreamConstants --> ObjectInputStream
DataOutput --> ObjectOutput
AutoCloseable --> ObjectOutput
ObjectOutput --> ObjectOutputStream
ObjectStreamConstants --> ObjectOutputStream
style Object fill:#f0f8ff,stroke:#696969
style InputStream fill:#f0f8ff,stroke:#696969
style ObjectInputStream fill:#f0f8ff,stroke:#696969
style OutputStream fill:#f0f8ff,stroke:#696969
style ObjectOutputStream fill:#f0f8ff,stroke:#696969
style AutoCloseable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
style DataInput fill:#f0f8ff,stroke:#4169e1
style DataOutput fill:#f0f8ff,stroke:#4169e1
style ObjectInput fill:#f0f8ff,stroke:#4169e1
style ObjectOutput fill:#f0f8ff,stroke:#4169e1
style ObjectStreamConstants fill:#f0f8ff,stroke:#4169e1
定义对象
- 对象必须实现
Serializable接口才能通过ObjectInputStream、ObjectOutputStream读写对象
- 实现
1 2 3
| class Cls implements Serializable { ... }
|
忽略字段
- 通过
transient关键字忽略指定字段进行序列化和反序列化
1 2 3
| class Cls implements Serializable { transient int field; }
|
指定版本
- 在序列化和反序列化的过程中,可以通过定义
serialVersionUID字段来指定版本,如果序列化和反序列化时版本不一致,会抛出异常
- 即便是没有显式定义
serialVersionUID字段,JVM在序列化时也会根据类的结构隐式的添加serialVersionUID字段,通过计算哈希值作为serialVersionUID字段的值
1 2 3
| class Cls implements Serializable { private static final long serialVersionUID = 1L; }
|
输入流
创建对象
1 2 3 4 5 6 7
| try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
|
读取数据
1
| Cls cls = (Cls) objectInputStream.readObject();
|
输出流
创建对象
1 2 3 4 5 6 7
| try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("<file>"))) { ... } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
|
写入数据
1 2 3
| Cls cls = new Cls();
objectOutputStream.writeObject(cls);
|
字节数组流
继承结构
graph TD
Object --> InputStream
InputStream --> ByteArrayInputStream
Object --> OutputStream
OutputStream --> ByteArrayOutputStream
AutoCloseable --> Closeable
Closeable --> InputStream
Closeable --> OutputStream
Flushable --> OutputStream
style Object fill:#f0f8ff,stroke:#696969
style InputStream fill:#f0f8ff,stroke:#696969
style ByteArrayInputStream fill:#f0f8ff,stroke:#696969
style OutputStream fill:#f0f8ff,stroke:#696969
style ByteArrayOutputStream fill:#f0f8ff,stroke:#696969
style AutoCloseable fill:#f0f8ff,stroke:#4169e1
style Closeable fill:#f0f8ff,stroke:#4169e1
style Flushable fill:#f0f8ff,stroke:#4169e1
输入流
创建对象
1 2 3 4 5
| try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream("".getBytes())) { ... } catch (IOException e) { e.printStackTrace(); }
|
读取数据
1
| char c = (char) byteArrayInputStream.read();
|
输出流
创建对象
1 2 3 4 5
| try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { ... } catch (IOException e) { e.printStackTrace(); }
|
写入数据
1
| byteArrayOutputStream.write("".getBytes());
|
获取数据
1
| byte[] bytes = byteArrayOutputStream.toByteArray();
|
完成