Java中的IO流就像水管系统,负责在程序和外部设备之间传输数据。为了更清晰理解,我们可以从三个维度分类,并配合生活化比喻:
一、按数据流向分类(水流方向)
-
输入流(读数据)
- 像吸管吸水:
InputStream(字节流)、Reader(字符流) - 场景:读取文件内容、接收网络数据
- 像吸管吸水:
-
输出流(写数据)
- 像水龙头放水:
OutputStream(字节流)、Writer(字符流) - 场景:保存文件、发送网络请求
- 像水龙头放水:
二、按数据类型分类(水管材质)
1. 字节流(万能水管)
- 特点:能传输所有类型数据(图片、视频、文本等)
- 基类:
InputStream、OutputStream - 常用类:
FileInputStream:读取本地文件(如:new FileInputStream("cat.jpg"))FileOutputStream:写入本地文件(如保存下载的图片)BufferedInputStream:带缓冲区(类似用货车批量运输,比卡车快)
- 场景:处理二进制文件(如图片、压缩包)、网络数据传输
2. 字符流(专用文字水管)
- 特点:自动处理字符编码(如UTF-8),适合文本
- 基类:
Reader、Writer - 常用类:
FileReader:读取文本文件(如new FileReader("note.txt"))FileWriter:写入文本文件(如记录日志)BufferedReader:带缓冲+行读取(readLine()读整行)
- 场景:处理纯文本(如CSV文件、配置文件)
三、按功能角色分类(水管配件)
1. 节点流(直连水源)
- 特点:直接操作数据源,如文件、内存
- 示例:
FileInputStream(字节流直连文件)FileReader(字符流直连文件)
2. 包装流(功能增强)
- 特点:包裹其他流,扩展功能
- 常见类型:
-
缓冲流(加速):
BufferedInputStream、BufferedReader// 读取提速10倍以上 try (BufferedReader br = new BufferedReader(new FileReader("bigfile.txt"))) { String line; while ((line = br.readLine()) != null) { /* 处理行 */ } } -
转换流(字节转字符):
InputStreamReader(指定编码)// 解决中文乱码问题 new InputStreamReader(new FileInputStream("data.txt"), "GBK"); -
数据流(处理基本类型):
DataInputStream(读写int、double等)DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin")); dos.writeInt(100); // 直接写整数 -
对象流(序列化):
ObjectInputStream(传输Java对象)// 保存对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat")); oos.writeObject(user); // User需实现Serializable接口
-
四、选择流的决策树
-
处理什么数据?
- 图片/视频/任意二进制 → 字节流
- 文本(尤其是含中文) → 字符流
-
需要什么功能?
- 基础读写 → 节点流(如
FileInputStream) - 需要缓冲 → +BufferedXXX
- 处理Java基本类型 → DataXXX
- 传输对象 → ObjectXXX
- 基础读写 → 节点流(如
-
是否需要指定编码?
- 是 → 用
InputStreamReader/OutputStreamWriter
- 是 → 用
五、经典场景对比
| 场景 | 推荐流组合 | 原因 |
|---|---|---|
| 复制图片文件 | FileInputStream + FileOutputStream | 字节流保证二进制完整性 |
| 读取大型文本文件 | BufferedReader + FileReader | 缓冲提升读取速度,支持按行读取 |
| 保存用户配置(UTF8) | FileWriter | 字符流自动处理编码(默认UTF8) |
| 网络数据传输 | BufferedInputStream + 字节流 | 缓冲减少网络IO次数 |
| 跨系统传输Java对象 | ObjectOutputStream | 序列化保持对象结构 |
六、避坑指南
-
资源泄漏:务必用
try-with-resources自动关闭流try (FileInputStream fis = new FileInputStream("file.txt")) { // 自动关闭流 } -
乱码问题:字符流默认使用系统编码,跨平台时显式指定:
new InputStreamReader(new FileInputStream("text.txt"), StandardCharsets.UTF_8); -
缓冲流关闭顺序:只需要关闭最外层缓冲流,内层流会自动关闭。
通过理解这些分类和场景,就能像搭积木一样组合出适合当前需求的IO方案。