Java IO流实现文件操作相关知识点
一、IO 流分类体系
分类标准 类型 基类(抽象类) 典型实现 适用场景
数据单位 字节流 InputStream / OutputStream FileInputStream, BufferedOutputStream 二进制文件(图片、视频、压缩包)
字符流 Reader / Writer FileReader, BufferedWriter 文本文件(.txt, .csv, .json)
功能角色 节点流 直接连接数据源 FileInputStream, FileReader 基础读写
处理流(包装流) 装饰其他流 BufferedInputStream, InputStreamReader 增强功能(缓冲、转换、对象序列化)
二、核心类与方法速查
字节流核心方法(InputStream / OutputStream)
· int read() – 读取一个字节,返回 0~255,流结束返回 -1
· int read(byte[] b) – 读取最多 b.length 字节,返回实际字节数
· int read(byte[] b, int off, int len) – 读取到指定偏移和长度
· void write(int b) / write(byte[] b) / write(byte[] b, int off, int len)
· void flush() – 强制将缓冲数据写出(对字节流一般意义不大,但某些装饰流需要)
· void close() – 释放系统资源
字符流核心方法(Reader / Writer)
· int read() – 读取单个字符(0~65535)
· int read(char[] cbuf) – 读取字符数组
· void write(String str) – 直接写字符串
· void write(char[] cbuf, int off, int len)
· void flush() / void close()
三、文件操作标准步骤(以复制文件为例)
1. 创建源和目标 File 对象(可选,也可直接传路径字符串)
2. 打开输入流和输出流(节点流或包装后的处理流)
3. 循环读写(使用缓冲区,避免单字节操作)
4. 关闭流(先开后关,后开先关;或使用 try-with-resources)
5. 处理异常(IOException 及子类)
四、常用实现类详解
类名 功能 注意点
FileInputStream / FileOutputStream 文件字节流 支持追加(构造器第二个参数 true)
FileReader / FileWriter 文件字符流 使用平台默认编码,跨平台易乱码
BufferedInputStream / BufferedOutputStream 缓冲字节流 默认 8KB 缓冲区,大幅提升性能
BufferedReader / BufferedWriter 缓冲字符流 readLine() 按行读取;newLine() 跨平台换行
InputStreamReader / OutputStreamWriter 字节流转字符流 必须指定字符集(如 UTF-8)
DataInputStream / DataOutputStream 读写 Java 基本类型 与平台无关,但文件格式固定
ObjectInputStream / ObjectOutputStream 对象序列化 需实现 Serializable,注意 serialVersionUID
PrintWriter / PrintStream 格式化输出 print() / printf() 很方便,不抛 IOException
五、缓冲流的原理与正确使用
· 原理:内部维护一个 byte/char 数组,一次性从硬盘读取多个字节到内存缓冲区,后续 read() 从缓冲区取;写时先写入缓冲区,满或 flush() 时真正调用 OS 写入。
· 正确用法:
```java
// 包装节点流
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
```
· 注意:
· 不要同时用缓冲流和节点流操作同一个文件,会相互干扰。
· 写完数据后务必调用 flush() 或 close(),否则可能丢失最后一批数据。
六、字符编码处理(极其重要)
· 乱码根源:写入时用 A 编码,读取时用 B 编码。
· 解决方案:读写文本文件时统一使用 InputStreamReader / OutputStreamWriter,并显式指定 StandardCharsets.UTF_8。
· 错误示例:new FileReader("a.txt") → 依赖系统编码(如 Windows GBK)。
· 正确示例:
```java
new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"), StandardCharsets.UTF_8));
```
· Java 11+ 简化:Files.newBufferedReader(Path.of("a.txt"), StandardCharsets.UTF_8)
七、性能优化技巧
操作 糟糕实践 优化实践
读取小文件 单字节循环 while((b=in.read())!=-1) 使用 byte[8192] 缓冲区或 BufferedInputStream
写文本文件 频繁调用 writer.write(String) 用 StringBuilder 拼接后一次性写入,或使用缓冲流
复制大文件 自己写 while 循环 改用 Files.copy()(底层利用通道或系统调用)
很多小文件随机读 每次打开新流 重用流,或使用 RandomAccessFile
八、异常处理与资源关闭
· 传统写法:嵌套 try-finally,在 finally 中对每个流判空并 close()(繁琐且容易遗漏)。
· 推荐写法:try-with-resources(Java 7+)
```java
try (FileInputStream fis = new FileInputStream("src");
FileOutputStream fos = new FileOutputStream("dst")) {
// 读写操作
} // 自动调用 close()
```
· 原则:实现了 AutoCloseable 的资源都应在 try 块头部声明,多个资源用分号隔开,关闭顺序与声明顺序相反。
九、常见操作场景与代码要点
1. 文本文件逐行读取
· 使用 BufferedReader.readLine(),读到 null 表示结束。
· 注意:readLine() 不包含换行符,需要手动添加或使用 newLine()。
2. 文件追加内容
· 字节流:new FileOutputStream(file, true)
· 字符流:new FileWriter(file, true)
· 缓冲流:同样在构造节点流时指定追加标志。
3. 复制文件(兼容二进制和文本)
· 优先使用字节流,即使复制文本文件也不会改变编码。
· 若必须用字符流,注意指定相同编码且不要丢失数据。
4. 读取文件属性(大小、最后修改时间)
· File.length(),File.lastModified(),但更推荐 NIO 的 Files 类。
5. 遍历目录中的文件
· File.listFiles() 返回数组,递归处理时注意 File.isDirectory() 判断。
十、重要注意事项(避坑指南)
1. flush() 不是必须立刻调用,但 close() 前数据未刷新可能导致丢失。BufferedWriter/PrintWriter 等必须显式或隐式刷新。
2. 不要混用字节流和字符流处理同一个文件,尤其不要用字符流读写二进制文件(会损坏数据)。
3. FileReader 和 FileWriter 默认编码问题:在跨平台项目中禁止直接使用,应使用包装流指定编码。
4. read(byte[] b) 返回值可能小于 b.length(尤其接近文件末尾),循环中必须使用实际读取长度。
5. 关闭流的顺序:先打开的后关闭。如果使用 try-with-resources 则无需关心。
6. 性能陷阱:一次只读一个字符/字节,在文件较大时性能急剧下降。
7. 随机访问:RandomAccessFile 支持 seek 和 getFilePointer,但它是独立于 InputStream/OutputStream 体系的。
十一、与 NIO(java.nio.file.Files)的对比
虽然题目要求“基于 IO 流”,但了解现代替代方案有助于选择:
特性 java.io java.nio.file.Files
简单复制 手动循环复制 Files.copy(Path, Path, StandardCopyOption)
读所有字节 循环读取 Files.readAllBytes()
读所有行 BufferedReader 循环 Files.readAllLines()
目录遍历 File.listFiles() 递归 Files.walk() / Files.list()
性能 适中 通常更好(借助底层通道和缓冲)
编码控制 需包装流 Files.newBufferedReader(path, charset) 一行搞定
建议:新项目中优先使用 Files 工具类,但仍需理解 IO 流原理,因为很多底层库和中间件仍然基于流。
更多推荐




所有评论(0)