Java IO 分类详解(传输方向 + 操作对象)
Java IO 的分类体系可从 传输方向(输入/输出)和 操作对象(字节/字符)两个维度展开,结合 节点流与处理流 的层次结构,形成完整的 IO 操作框架。以下是详细解析:
一、按传输方向分类
1. 输入流(Input Stream)
- 作用:从数据源读取数据(如文件、网络、内存)。
- 核心接口:
- 字节输入流:
InputStream
(抽象类)FileInputStream
:读取文件。ByteArrayInputStream
:从字节数组读取。DataInputStream
:读取基本类型(readInt()
,readUTF()
)。ObjectInputStream
:反序列化对象。
- 字符输入流:
Reader
(抽象类)FileReader
:读取文本文件。InputStreamReader
:将字节流转换为字符流。BufferedReader
:缓冲字符流,支持readLine()
。
- 字节输入流:
2. 输出流(Output Stream)
- 作用:向目标写入数据(如文件、网络、内存)。
- 核心接口:
- 字节输出流:
OutputStream
(抽象类)FileOutputStream
:写入文件。ByteArrayOutputStream
:向字节数组写入。DataOutputStream
:写入基本类型。ObjectOutputStream
:序列化对象。
- 字符输出流:
Writer
(抽象类)FileWriter
:写入文本文件。OutputStreamWriter
:将字符流转换为字节流。BufferedWriter
:缓冲字符流,支持newLine()
。
- 字节输出流:
二、按操作对象分类
1. 字节流(Byte Stream)
- 单位:以
byte
(8位)为单位操作数据。 - 适用场景:
- 二进制文件(如图片、音频、视频)。
- 网络传输(TCP/UDP 协议基于字节流)。
- 跨平台数据交换(避免字符编码问题)。
- 核心类:
InputStream
/OutputStream
及其子类。
2. 字符流(Character Stream)
- 单位:以
char
(16位Unicode字符)为单位操作数据。 - 适用场景:
- 文本文件(如
.txt
,.csv
,.json
)。 - 字符串处理(自动处理字符编码转换)。
- 文本文件(如
- 核心类:
Reader
/Writer
及其子类。
- 编码处理:
- 显式指定字符集(如
StandardCharsets.UTF_8
):new InputStreamReader(new FileInputStream("file.txt"), "UTF-8");
- 显式指定字符集(如
三、节点流 vs 处理流
1. 节点流(Node Stream)
- 定义:直接操作数据源或目标的流。
- 示例:
FileInputStream
:直接读取文件。Socket.getInputStream()
:从网络套接字读取数据。
2. 处理流(Processing Stream)
- 定义:包装其他流,增强功能(如缓冲、转换、格式化)。
- 常见处理流:
- 缓冲流:
BufferedInputStream
/BufferedOutputStream
:减少直接IO次数。BufferedReader
/BufferedWriter
:支持按行读写。
- 转换流:
InputStreamReader
/OutputStreamWriter
:字节流与字符流互转。
- 数据流:
DataInputStream
/DataOutputStream
:读写基本类型。
- 对象流:
ObjectInputStream
/ObjectOutputStream
:序列化/反序列化对象。
- 缓冲流:
3. 组合模式示例
// 读取文件内容并逐行处理
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("data.txt"),
StandardCharsets.UTF_8
))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
四、分类选择策略
场景 | 推荐流类型 | 原因 |
---|---|---|
读取文本文件 | BufferedReader 包装 FileReader | 支持按行读取,自动处理换行符 |
写入二进制数据 | DataOutputStream 包装 FileOutputStream | 支持直接写入 int /double 等基本类型 |
网络传输(TCP) | BufferedInputStream /BufferedOutputStream | 缓冲减少网络IO次数 |
跨平台数据交换 | 字节流(如 DataInputStream ) | 避免字符编码问题 |
对象持久化 | ObjectOutputStream 包装 FileOutputStream | 实现序列化 |
五、高级主题
1. NIO 通道与缓冲区
- 通道(Channel):双向数据传输(如
FileChannel
)。 - 缓冲区(Buffer):数据容器(如
ByteBuffer
)。 - 示例:
try (FileChannel channel = FileChannel.open(Paths.get("data.txt"), StandardOpenOption.READ)) { ByteBuffer buffer = ByteBuffer.allocate(1024); while (channel.read(buffer) > 0) { buffer.flip(); // 切换为读模式 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } buffer.clear(); // 清空缓冲区 } }
2. 零拷贝(Zero-Copy)
- 场景:大文件传输。
- 实现:通过
FileChannel.transferTo()
/transferFrom()
避免数据在内核空间和用户空间拷贝。
3. 文件锁(FileLock)
- 作用:控制多进程/线程对文件的并发访问。
- 示例:
try (RandomAccessFile file = new RandomAccessFile("data.txt", "rw"); FileChannel channel = file.getChannel(); FileLock lock = channel.lock()) { // 独占锁 // 读写文件 }
六、最佳实践
-
明确字符编码:
- 避免依赖平台默认编码,始终显式指定(如
StandardCharsets.UTF_8
)。
- 避免依赖平台默认编码,始终显式指定(如
-
优先使用缓冲流:
- 减少直接IO操作次数,提升性能。
-
资源自动管理:
- 使用 try-with-resources 确保流关闭:
try (InputStream in = new FileInputStream("file.txt"); OutputStream out = new FileOutputStream("copy.txt")) { // 复制逻辑 }
- 使用 try-with-resources 确保流关闭:
-
选择合适的流类型:
- 二进制数据用字节流,文本数据用字符流。
通过理解Java IO的分类体系,可以更精准地选择工具类,提升代码效率和可维护性。实际开发中需结合场景权衡传统IO与NIO的适用性。