Java IO 流全解:从基础到实战,一篇吃透 IO 核心知识
前言
IO(Input/Output)流是 Java 开发的核心基础,也是面试高频考点,无论是文件读写、网络通信,还是数据序列化,都离不开 IO 流的支撑。本文将从 IO 流的分类、核心 API、字节流 / 字符流、对象流、NIO 等维度,全面详细讲解 Java IO 流的知识体系,搭配实战代码示例,帮你彻底掌握 IO 流的核心逻辑与应用场景。
一、IO 流核心概念
1. 什么是 IO 流
IO 流是 Java 中用于数据传输的抽象概念,本质是数据的流动通道,分为输入流(Input)和输出流(Output):
- 输入流:从外部设备(文件、网络、键盘等)读取数据到程序内存中;
- 输出流:将程序内存中的数据写入到外部设备(文件、网络、显示器等)。
2. IO 流的分类(核心)
Java IO 流的分类维度有 3 个,需重点掌握:
(1)按数据传输单位分
- 字节流:以字节(Byte) 为单位传输,可处理所有类型数据(文本、图片、音频、视频等),基类为
InputStream(输入)、OutputStream(输出); - 字符流:以字符(Char) 为单位传输,仅能处理文本数据,自动适配编码(UTF-8、GBK 等),基类为
Reader(输入)、Writer(输出)。
(2)按数据流向分
- 输入流:
InputStream、Reader; - 输出流:
OutputStream、Writer。
(3)按功能角色分
- 节点流:直接连接数据源(文件、网络等),是数据传输的 “直接通道”,如
FileInputStream、FileReader; - 处理流(包装流):基于节点流封装,增强功能(缓冲、序列化、编码转换等),如
BufferedInputStream、ObjectOutputStream。
3. IO 流的继承体系(必记)
plaintext
# 字节流基类
InputStream(抽象)
├── FileInputStream(文件字节输入流)
├── BufferedInputStream(缓冲字节输入流)
├── ObjectInputStream(对象输入流)
└── ...
OutputStream(抽象)
├── FileOutputStream(文件字节输出流)
├── BufferedOutputStream(缓冲字节输出流)
├── ObjectOutputStream(对象输出流)
└── ...
# 字符流基类
Reader(抽象)
├── FileReader(文件字符输入流)
├── BufferedReader(缓冲字符输入流)
└── ...
Writer(抽象)
├── FileWriter(文件字符输出流)
├── BufferedWriter(缓冲字符输出流)
└── ...
二、字节流(InputStream/OutputStream)
字节流是 IO 流的基础,支持所有数据类型,核心 API 和实战如下:
1. FileInputStream(文件字节输入流)
作用:读取文件中的字节数据,适用于非文本文件(图片、音频)和文本文件。
核心方法
int read():读取一个字节,返回字节值(0-255),读取到文件末尾返回 - 1;int read(byte[] b):读取字节数组,返回读取的字节数;void close():关闭流,释放资源(必须手动关闭,避免资源泄漏)。
实战:读取图片文件
java
运行
import java.io.FileInputStream;
import java.io.IOException;
public class ByteInputDemo {
public static void main(String[] args) {
// 声明流对象(try-with-resources自动关闭流,推荐)
try (FileInputStream fis = new FileInputStream("test.jpg")) {
byte[] buffer = new byte[1024]; // 缓冲区,提升读取效率
int len; // 记录每次读取的字节数
while ((len = fis.read(buffer)) != -1) {
// 处理读取的字节数据(如写入新文件、解析数据等)
System.out.println("读取字节数:" + len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. FileOutputStream(文件字节输出流)
作用:将字节数据写入文件,支持覆盖写入和追加写入。
核心方法
void write(int b):写入一个字节;void write(byte[] b):写入字节数组;void write(byte[] b, int off, int len):写入字节数组的指定部分;- 构造器:
FileOutputStream(String name, boolean append),append=true表示追加写入,默认 false(覆盖)。
实战:写入文本到文件
java
运行
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteOutputDemo {
public static void main(String[] args) {
String content = "Java IO流学习笔记";
try (FileOutputStream fos = new FileOutputStream("io.txt", true)) { // 追加模式
fos.write(content.getBytes()); // 字符串转字节数组写入
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 缓冲字节流(BufferedInputStream/BufferedOutputStream)
作用:基于节点流封装,内置缓冲区(默认 8KB),减少磁盘 IO 次数,大幅提升读写效率,是开发中常用的处理流。
实战:缓冲流复制文件
java
运行
import java.io.*;
public class BufferedCopyDemo {
public static void main(String[] args) {
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("target.jpg"))
) {
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.flush(); // 刷新缓冲区,确保数据写入文件
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、字符流(Reader/Writer)
字符流专为文本数据设计,自动处理编码问题,避免中文乱码,核心 API 和实战如下:
1. FileReader(文件字符输入流)
作用:读取文本文件中的字符数据,默认使用系统编码(Windows 为 GBK,Linux 为 UTF-8)。
核心方法
int read():读取一个字符,返回字符的 ASCII 码,末尾返回 - 1;int read(char[] cbuf):读取字符数组,返回读取的字符数。
2. FileWriter(文件字符输出流)
作用:将字符数据写入文本文件,支持追加写入。
实战:字符流读写文本
java
运行
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CharDemo {
public static void main(String[] args) {
// 读取文本
try (FileReader fr = new FileReader("io.txt")) {
char[] buffer = new char[1024];
int len;
while ((len = fr.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
// 写入文本(追加)
try (FileWriter fw = new FileWriter("io.txt", true)) {
fw.write("\n字符流写入测试");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 缓冲字符流(BufferedReader/BufferedWriter)
作用:内置缓冲区,支持按行读写(readLine()、newLine()),是文本处理的首选。
实战:按行读取文本
java
运行
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderDemo {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("io.txt"))) {
String line;
// 按行读取,直到末尾返回null
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 转换流(InputStreamReader/OutputStreamWriter)
作用:字节流与字符流的桥梁,可指定编码格式,解决中文乱码问题(核心!)。
实战:指定 UTF-8 编码读写文件
java
运行
import java.io.*;
public class ConvertStreamDemo {
public static void main(String[] args) {
// 字节流转字符流,指定UTF-8编码
try (
InputStreamReader isr = new InputStreamReader(new FileInputStream("io.txt"), "UTF-8");
BufferedReader br = new BufferedReader(isr)
) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、对象流(ObjectInputStream/ObjectOutputStream)
对象流用于对象的序列化与反序列化,可将 Java 对象写入文件或网络,也可读取还原对象,是分布式开发、缓存存储的核心技术。
1. 核心概念
- 序列化:将内存中的 Java 对象转换为字节序列,写入外部设备(
ObjectOutputStream); - 反序列化:将外部设备中的字节序列还原为 Java 对象(
ObjectInputStream); - 序列化要求:对象必须实现
Serializable接口(标记接口,无抽象方法),否则抛出NotSerializableException。
2. 实战:对象序列化与反序列化
(1)定义可序列化的实体类
java
运行
import java.io.Serializable;
// 实现Serializable接口,支持序列化
public class Student implements Serializable {
// 序列化版本ID,确保反序列化时类的一致性
private static final long serialVersionUID = 1L;
private String name;
private int age;
// 构造器、get/set、toString 省略
}
(2)序列化(写入对象)
java
运行
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class ObjectOutputDemo {
public static void main(String[] args) {
Student student = new Student("张三", 18);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.dat"))) {
oos.writeObject(student); // 序列化对象
} catch (Exception e) {
e.printStackTrace();
}
}
}
(3)反序列化(读取对象)
java
运行
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ObjectInputDemo {
public static void main(String[] args) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.dat"))) {
Student student = (Student) ois.readObject(); // 反序列化
System.out.println(student);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. 对象流的 “多对象” 陷阱(高频面试)
坑点
连续writeObject()写入同一个对象(修改属性后),反序列化读取的始终是第一次写入的旧对象。
原因
ObjectOutputStream 内部维护对象引用缓存表,避免重复序列化,第二次写入仅存储引用编号,不重新序列化。
解决方案
- 调用
reset()清空缓存(推荐):oos.reset();后再写入; - 每次新建
ObjectOutputStream:避免缓存复用; - 重写
removeClassDesc方法:强制移除类描述符缓存(高级用法)。
五、NIO(非阻塞 IO)
Java NIO(New IO/Non-blocking IO)是 Java 1.4 引入的新 IO 模型,解决了传统 BIO(阻塞 IO)的并发瓶颈,是现代高并发网络编程的基础。
1. BIO vs NIO 核心对比
表格
| 维度 | BIO(阻塞 IO) | NIO(非阻塞 IO) |
|---|---|---|
| IO 模型 | 阻塞式 | 非阻塞式 |
| 数据传输 | 流式(Stream),单向 | 块式(Channel+Buffer),双向 |
| 线程模型 | 一连接一线程,并发低 | 一线程多连接,并发高 |
| 核心组件 | InputStream/OutputStream | Buffer、Channel、Selector |
| 适用场景 | 低并发、小流量 | 高并发、长连接(IM、网关) |
2. NIO 三大核心组件
(1)Buffer(缓冲区)
- 本质是内存数组,用于存储 NIO 传输的数据,所有数据都通过 Buffer 交互;
- 核心属性:
capacity(容量)、position(当前位置)、limit(限制); - 常用类型:
ByteBuffer(最常用)、CharBuffer、IntBuffer等。
(2)Channel(通道)
- 数据传输的双向通道,支持读、写、读写同时操作;
- 常用类型:
FileChannel(文件通道)、SocketChannel(网络客户端通道)、ServerSocketChannel(网络服务端通道)。
(3)Selector(选择器)
- 核心组件,用于监听多个 Channel 的事件(连接、读、写);
- 一个 Selector 可管理多个 Channel,实现单线程处理多连接,大幅提升并发能力。
3. NIO 实战:文件复制
java
运行
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioCopyDemo {
public static void main(String[] args) {
try (
FileChannel inChannel = new FileInputStream("source.jpg").getChannel();
FileChannel outChannel = new FileOutputStream("target.jpg").getChannel()
) {
ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配缓冲区
while (inChannel.read(buffer) != -1) {
buffer.flip(); // 切换为读模式
outChannel.write(buffer);
buffer.clear(); // 清空缓冲区
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
六、IO 流使用注意事项
- 流的关闭:使用
try-with-resources语法自动关闭流,避免资源泄漏; - 编码问题:处理中文文本时,使用转换流指定编码(UTF-8),避免乱码;
- 缓冲流优先:读写文件时,优先使用缓冲流,提升 IO 效率;
- 序列化安全:序列化类需指定
serialVersionUID,避免类修改后反序列化失败; - NIO 适用场景:高并发网络编程用 NIO,普通文件读写用传统 IO 即可。
七、总结
本文全面讲解了 Java IO 流的核心知识,从基础的字节流 / 字符流,到进阶的对象流、NIO,覆盖了 IO 流的分类、API、实战和面试考点。
- 基础应用:文件读写、文本处理,优先使用缓冲字节流 / 字符流;
- 进阶应用:对象序列化、网络通信,使用对象流和 NIO;
- 核心原则:合理选择流类型,及时关闭流,优化 IO 效率。
掌握 IO 流是 Java 开发的必备技能,后续可深入学习 NIO.2(AIO)、Netty 等高性能 IO 框架,进一步提升高并发编程能力。
更多推荐




所有评论(0)