01. IO 流分类
Java IO 按流向分为输入流和输出流,按数据单位分为字节流和字符流。字节流以 byte 为单位,后缀是 Stream(InputStream/OutputStream),适合处理图片、视频等二进制。字符流以 char 为单位,后缀是 Reader/Writer,适合处理文本。IO 流用了装饰者模式,一层套一层。
java
// 字节流 - 复制文件
FileInputStream fis = new FileInputStream("source.jpg");
FileOutputStream fos = new FileOutputStream("dest.jpg");
// 字符流 - 读取文本
FileReader reader = new FileReader("text.txt");
BufferedReader br = new BufferedReader(reader);02. 文件读写基础
最基础的读文件用 FileReader 或 FileInputStream,写文件用 FileWriter 或 FileOutputStream。但裸用的效率很低,一次读一个字节或字符。套一个 BufferedReader 或 BufferedInputStream 加上缓冲区,效率能提高几十倍。读文本用 readLine 一行行读最方便。
java
// 读文本文件
StringBuilder content = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
content.append(line).append("\n");
}
}
// 写文件
try (BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"))) {
bw.write("Hello, 世界");
bw.newLine();
}文件操作一定用 try-with-resources,避免忘关流造成资源泄漏。
03. NIO 和 Path/Files
JDK7 引入的 NIO.2 提供了 Path 和 Files 工具类,操作文件比以前简单多了。Files.readAllLines 一行代码读整个文件,Files.write 一行代码写文件。Path 替代了难用的 File 类,Paths.get 创建路径对象。用 NIO 的 API 处理小文件比传统 IO 方便太多。
java
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
Path path = Paths.get("data.txt");
// 一行读整个文件
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
// 一行写文件
Files.write(path, Arrays.asList("第一行", "第二行"), StandardCharsets.UTF_8);
// 检查文件
boolean exists = Files.exists(path);
long size = Files.size(path);处理小文件(几 MB 以内)直接用 Files 工具类,大文件还是用流式读取。
04. 对象序列化
序列化就是把 Java 对象转成字节序列存起来或网络传输。类需要实现 Serializable 标记接口,用 ObjectOutputStream 写出,ObjectInputStream 读入。serialVersionUID 是序列化版本号,不显式写的话 jvm 自动生成一个,改了类容易反序列化失败。
java
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient String password; // 不序列化
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.obj"))) {
oos.writeObject(new User("小明", "123456"));
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.obj"))) {
User user = (User) ois.readObject();
}transient 修饰的字段不会被序列化,适合密码之类的敏感数据。
05. 编码问题
编码问题是 IO 最常见的坑。文件以什么编码存的就要以什么编码读。Windows 默认 GBK,Mac/Linux 默认 UTF-8,跨平台最容易乱码。InputStreamReader 和 OutputStreamWriter 可以指定编码,把字节流转成字符流。NIO 的 Files 读取时也指定 StandardCharsets 编码。
java
// 指定编码读取
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream("test.txt"), StandardCharsets.UTF_8))) {
String line = br.readLine();
}
// NIO 方式指定编码
String content = Files.readString(Path.of("test.txt"), StandardCharsets.UTF_8);处理中文内容时一定要显式指定 UTF-8 编码,不要依赖系统默认编码。
知识测验
第 1/4 题正确 0
Java IO 中字节流和字符流的根本区别?
下一节
下一节 多线程