Java 流(Stream)分类、用途与性能分析
Java中的I/O流提供了丰富的类库来处理输入输出操作。
主要分为字节流和字符流两大类。
下面我将从分类、用途和性能三个方面进行详细说明。
一、流的分类
1. 按数据单位分类
字节流 (Byte Streams)
基础类:
InputStream
和OutputStream
文件操作:
FileInputStream
,FileOutputStream
缓冲流:
BufferedInputStream
,BufferedOutputStream
对象序列化:
ObjectInputStream
,ObjectOutputStream
数据转换:
DataInputStream
,DataOutputStream
字符流 (Character Streams)
基础类:
Reader
和Writer
文件操作:
FileReader
,FileWriter
缓冲流:
BufferedReader
,BufferedWriter
转换流:
InputStreamReader
,OutputStreamWriter
2. 按功能分类
节点流 (Node Streams)
直接与数据源连接的流
示例:
FileInputStream
,FileReader
处理流 (Processing Streams)
对节点流或其他处理流进行包装
提供额外功能(缓冲、数据类型转换等)
示例:
BufferedInputStream
,BufferedReader
二、主要流类的用途
字节流用途
FileInputStream/FileOutputStream
用于读写二进制文件
适合图像、音频、视频等非文本文件
BufferedInputStream/BufferedOutputStream
提供缓冲功能,减少I/O操作次数
提高读写性能
DataInputStream/DataOutputStream
读写基本数据类型和字符串
保持数据的原始格式
ObjectInputStream/ObjectOutputStream
用于对象的序列化和反序列化
字符流用途
FileReader/FileWriter
用于读写文本文件
自动处理字符编码
BufferedReader/BufferedWriter
提供缓冲功能
BufferedReader
特有的readLine()
方法
InputStreamReader/OutputStreamWriter
字节流与字符流之间的桥梁
可以指定字符编码
三、性能比较与最佳实践
性能比较
无缓冲 vs 缓冲流
无缓冲流每次读写都直接操作底层资源,性能较差
缓冲流通过内存缓冲区减少I/O操作次数,性能显著提升
典型缓冲区大小:8KB (可调整)
字节流 vs 字符流
处理文本时字符流性能更好(避免了字节-字符转换)
处理二进制数据必须使用字节流
大文件处理
缓冲流对大型文件性能提升更明显
对于超大文件,考虑使用内存映射文件(MappedByteBuffer)
实践分析
始终使用缓冲流
// 不好的做法 FileInputStream fis = new FileInputStream("file.txt");// 好的做法 InputStream is = new BufferedInputStream(new FileInputStream("file.txt"));
正确处理字符编码
// 指定UTF-8编码 Reader reader = new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8);
使用try-with-resources确保资源释放
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {String line;while ((line = br.readLine()) != null) {// 处理每一行} }
根据场景选择合适的流
文本处理:字符流
二进制数据:字节流
网络通信:缓冲流 + 适当设置缓冲区大小
大文件处理优化
使用NIO的
FileChannel
和MappedByteBuffer
处理超大文件分块读取处理,避免内存溢出
性能测试
public class StreamPerformanceTest {public static void main(String[] args) throws IOException {String filePath = "large_file.txt";// 测试无缓冲字节流long start = System.currentTimeMillis();try (InputStream is = new FileInputStream(filePath)) {while (is.read() != -1);}System.out.println("FileInputStream: " + (System.currentTimeMillis() - start) + "ms");// 测试缓冲字节流start = System.currentTimeMillis();try (InputStream is = new BufferedInputStream(new FileInputStream(filePath))) {while (is.read() != -1);}System.out.println("BufferedInputStream: " + (System.currentTimeMillis() - start) + "ms");// 测试缓冲字符流start = System.currentTimeMillis();try (Reader reader = new BufferedReader(new FileReader(filePath))) {while (reader.read() != -1);}System.out.println("BufferedReader: " + (System.currentTimeMillis() - start) + "ms");}
}
总结
选择原则:根据数据类型(文本/二进制)选择字符流或字节流,优先使用缓冲流
性能关键:减少实际I/O操作次数是提高性能的关键
编码注意:处理文本时始终明确字符编码
资源管理:使用try-with-resources确保流正确关闭
高级场景:对于超大规模I/O,考虑NIO或内存映射文件
正确选择和使用Java I/O流可以显著影响应用程序的性能和可靠性。