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流可以显著影响应用程序的性能和可靠性。