Java IO 体系
IO 核心认知
- IO = Input/Output,用于数据传输(文件、网络、内存、控制台)
- Java IO 核心是流(Stream):数据像水流一样有序传输
- 流是单向的:要么读、要么写
- 所有 IO 类都在 java.io. 包下
1. IO 流三大分类方式(必须背)
1.1 按数据流向
- 输入流(Input):读数据 → 外部 → 程序
- 输出流(Output):写数据 → 程序 → 外部
1.2 按操作数据单位
- 字节流:以 byte 为单位,万能流,支持所有文件(图片/视频/文本)
- 字符流:以 char 为单位,只支持纯文本,自带编码
1.3 按功能
- 节点流(低级流):直接连接数据源(文件、数组、管道)
- 处理流(包装流):包装节点流,增强功能(缓冲、对象、序列化)
2. IO 四大抽象基类(所有流的爹)
所有流都继承这 4 个抽象类:
- 字节输入流:
InputStream - 字节输出流:
OutputStream - 字符输入流:
Reader - 字符输出流:
Writer
3. 字节流体系(万能流)
3.1 FileInputStream / FileOutputStream(文件节点流)
- 作用:直接读写文件
- 适用:所有文件类型
- 特点:无缓冲区,读写效率低
FileInputStream fis = new FileInputStream("a.jpg");
FileOutputStream fos = new FileOutputStream("b.jpg");
3.2 BufferedInputStream / BufferedOutputStream(缓冲字节流)
- 包装流,内置 8192 字节缓冲区
- 减少磁盘 IO,速度极快
- 企业开发首选
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg"));
3.3 ByteArrayInputStream / ByteArrayOutputStream(内存数组流)
- 操作内存中的 byte[]
- 不涉及磁盘,速度最快
- 常用于缓存、数据中转
3.4 ObjectInputStream / ObjectOutputStream(对象流)
- 对象序列化 / 反序列化
- 把对象写入文件/网络
- 对象必须实现 Serializable 接口
transient修饰的属性不参与序列化
3.5 DataInputStream / DataOutputStream(数据流)
- 按 Java 基本数据类型读写:int、double、boolean、UTF 字符串
- 常用于自定义协议、网络传输、二进制存储
3.6 PrintStream
- 打印流,
System.out就是它 - 不会抛 IO 异常
- 可打印各种数据
4. 字符流体系(纯文本专用)
4.1 FileReader / FileWriter(文件字符流)
- 直接读写文本文件
- 缺陷:使用系统默认编码,跨平台必乱码
4.2 BufferedReader / BufferedWriter(缓冲字符流)
- 高效、支持按行读写
- 特有方法:
readLine()读一行newLine()写换行
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
4.3 InputStreamReader / OutputStreamWriter(转换流)
- 字节流 ↔ 字符流 的桥梁
- 可以指定编码(UTF-8/GBK)
- 解决中文乱码唯一方案
- 企业文本 IO 必须用它
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"), "UTF-8");
4.4 CharArrayReader / CharArrayWriter
字符数组流,操作内存 char 数组
4.5 PrintWriter
字符打印流,功能同 PrintStream
5. IO 流完整体系图谱(必背)
InputStream(字节输入)
├── FileInputStream
├── ByteArrayInputStream
├── FilterInputStream
│ ├── BufferedInputStream
│ ├── DataInputStream
│ └── ObjectInputStream
└── PipedInputStream(线程管道)
OutputStream(字节输出)
├── FileOutputStream
├── ByteArrayOutputStream
├── FilterOutputStream
│ ├── BufferedOutputStream
│ ├── DataOutputStream
│ ├── ObjectOutputStream
│ └── PrintStream
└── PipedOutputStream
Reader(字符输入)
├── InputStreamReader(转换流)
│ └── FileReader
├── BufferedReader
├── CharArrayReader
└── StringReader
Writer(字符输出)
├── OutputStreamWriter(转换流)
│ └── FileWriter
├── BufferedWriter
├── CharArrayWriter
├── StringWriter
└── PrintWriter
6. 核心方法(必须掌握)
6.1 字节流方法
// 读
int read(); // 读一个字节,-1结束
int read(byte[] buf); // 读一个数组
void close();
// 写
void write(int b);
void write(byte[] buf);
void write(byte[] buf,int off,int len);
void flush();
void close();
6.2 字符流方法
int read();
int read(char[] cbuf);
String readLine();
void write(String str);
void write(char[] cbuf);
void newLine();
void flush();
7. 各类流使用场景(企业开发标准)
7.1 复制任意文件(图片/视频/文件)
BufferedInputStream + BufferedOutputStream
7.2 读写文本文件、解决乱码
BufferedReader + InputStreamReader(指定UTF-8)
7.3 网络通信接收字符串
Socket 得到字节流 → 转换流 → 缓冲字符流
7.4 对象持久化/网络传输对象
ObjectInputStream / ObjectOutputStream
7.5 二进制协议、基本类型数据传输
DataInputStream / DataOutputStream
7.6 内存快速读写
ByteArrayInputStream / ByteArrayOutputStream
8. 企业开发 IO 巨坑(高频 BUG 合集)
坑1:流忘记关闭 → 文件句柄泄漏 → 服务器崩溃
- 表现:Too many open files
- 解决方案:JDK7+ try-with-resources
坑2:字符流不指定编码 → 中文乱码
- FileReader/FileWriter 用系统编码
- 必须用 InputStreamReader 指定 UTF-8
坑3:flush 忘记调用 → 数据写不出去
- 缓冲区满才自动刷
- 手动调用 flush 或 close 才会落地
坑4:close() 会自动 flush,但不要依赖
- 业务逻辑异常直接跳走,数据丢失
坑5:循环逐字节读写,性能爆炸
- 必须用数组缓冲:byte[8192] / char[8192]
坑6:序列化版本号不一致 → 反序列化失败
- 实现 Serializable 建议显式声明:
private static final long serialVersionUID = 1L;
坑7:transient 变量被序列化(误解)
- transient 修饰的属性不会序列化,默认值为 null / 0
坑8:装饰流关闭会自动关闭底层流
- 只需要关闭最外层流
坑9:文本文件用字节流直接转字符串乱码
- 必须用转换流指定编码
坑10:RandomAccessFile 并发不安全
- 多线程操作同一文件会错乱
9. try-with-resources 自动关闭(企业标准)
实现 AutoCloseable 接口的流都能自动关闭:
try (
FileInputStream fis = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
BufferedReader br = new BufferedReader(isr)
) {
String line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
无需 finally,自动关闭,不会泄漏
10. 传统 BIO 与 NIO 区别(扩展)
10.1 BIO(传统 IO)
- 面向流
- 阻塞 IO
- 单向
- 无缓冲区
- 简单低效
- 适合低并发
10.2 NIO(New IO / Non-blocking IO)
- 面向缓冲区 Buffer
- 非阻塞
- 双向通道 Channel
- 多路复用 Selector
- 高并发、高性能
- 适合网络通信(Netty 基于 NIO)
11. 高频 IO 面试题(100% 考)
- 字节流与字符流区别?
- 什么是节点流、处理流?
- 转换流作用与使用场景?
- 缓冲流为什么快?
- 序列化是什么?需要注意什么?
- try-with-resources 原理?
- flush 和 close 区别?
- 为什么字符流会乱码,字节流不会?
- 数据流作用?
- BIO 与 NIO 区别?