1. Java IO 流基础概念与核心设计
Java IO(Input/Output)是Java语言中处理输入输出的核心API,它提供了丰富的类库来支持各种数据源的读写操作。在实际开发中,IO操作几乎无处不在,无论是文件读写、网络通信还是内存数据处理,都离不开IO流的支持。
1.1 IO 流的基本分类
Java IO流按照不同的维度可以分为多种类型:
-
按数据流向:
- 输入流(Input Stream):从数据源读取数据到程序中
- 输出流(Output Stream):从程序写出数据到目标位置
-
按数据处理单位:
- 字节流:以字节(8位)为单位进行数据传输
- 字符流:以字符(16位Unicode)为单位进行数据传输
-
按功能角色:
- 节点流:直接操作数据源的流
- 处理流:对现有流进行包装和增强的流
1.2 IO 流的类层次结构
Java IO的40多个类都派生自4个抽象基类:
code复制InputStream
├── FileInputStream
├── ByteArrayInputStream
├── FilterInputStream
│ ├── BufferedInputStream
│ ├── DataInputStream
│ └── ...
└── ...
OutputStream
├── FileOutputStream
├── ByteArrayOutputStream
├── FilterOutputStream
│ ├── BufferedOutputStream
│ ├── DataOutputStream
│ └── ...
└── ...
Reader
├── InputStreamReader
│ └── FileReader
├── BufferedReader
├── StringReader
└── ...
Writer
├── OutputStreamWriter
│ └── FileWriter
├── BufferedWriter
├── StringWriter
└── ...
1.3 为什么需要字节流和字符流两种体系?
在实际开发中,字节流和字符流各有其适用场景:
-
字节流的优势:
- 适合处理二进制数据(如图片、音频、视频等)
- 处理效率高,没有字符编码转换的开销
- 可以处理任意类型的数据
-
字符流的必要性:
- 专门为文本处理设计,解决了字节流处理文本时的编码问题
- 提供了更方便的文本操作方法(如按行读取)
- 自动处理字符编码转换(如UTF-8到Unicode)
经验分享:在实际项目中,我通常会遵循这样的原则:如果是文本文件(如.properties、.txt等)优先使用字符流;如果是二进制文件(如图片、压缩包等)则必须使用字节流。混合使用可能会导致数据损坏或乱码问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 字节流详解与实战应用
字节流是Java IO中最基础的流类型,它直接操作原始字节数据,不进行任何转换处理。
2.1 InputStream 字节输入流
InputStream是所有字节输入流的抽象基类,定义了读取字节数据的基本方法。
2.1.1 核心方法解析
java复制public abstract class InputStream implements Closeable {
// 读取下一个字节,返回0-255的int值,-1表示结束
public abstract int read() throws IOException;
// 读取字节到数组b中,返回实际读取的字节数
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
// 读取字节到数组b的指定位置,off为偏移量,len为最大读取长度
public int read(byte b[], int off, int len) throws IOException {
// 实现细节...
}
// 跳过n个字节,返回实际跳过的字节数
public long skip(long n) throws IOException {
// 实现细节...
}
// 返回可读取的字节数
public int available() throws IOException {
return 0;
}
// 关闭流,释放资源
public void close() throws IOException {}
// JDK9新增方法:读取所有字节
public byte[] readAllBytes() throws IOException {
// 实现细节...
}
// JDK9新增方法:读取指定数量的字节
public int readNBytes(byte[] b, int off, int len) throws IOException {
// 实现细节...
}
// JDK9新增方法:将数据直接传输到输出流
public long transferTo(OutputStream out) throws IOException {
// 实现细节...
}
}
2.1.2 FileInputStream 实战示例
java复制// 使用try-with-resources确保资源自动关闭
try (InputStream fis = new FileInputStream("example.dat")) {
// 查看剩余可用字节数
System.out.println("Available bytes: " + fis.available());
// 跳过前10个字节
long skipped = fis.skip(10);
System.out.println("Skipped " + skipped + " bytes");
// 逐个字节读取
int byteData;
while ((byteData = fis.read()) != -1) {
System.out.print((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
性能提示:单字节读取(read())效率很低,实际开发中应尽量使用批量读取(read(byte[]))方法。对于大文件,建议设置缓冲区大小为4KB-8KB(4096-8192字节),这是经过实践验证的较优值。
2.2 OutputStream 字节输出流
OutputStream是所有字节输出流的抽象基类,定义了写出字节数据的基本方法。
2.2.1 核心方法解析
java复制public abstract class OutputStream implements Closeable, Flushable {
// 写出单个字节
public abstract void write(int b) throws IOException;
// 写出字节数组
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
// 写出字节数组的指定部分
public void write(byte b[], int off, int len) throws IOException {
// 实现细节...
}
// 刷新输出缓冲区
public void flush() throws IOException {}
// 关闭流,释放资源
public void close() throws IOException {}
}
2.2.2 FileOutputStream 实战示例
java复制// 使用try-with-resources确保资源自动关闭
try (OutputStream fos = new FileOutputStream("output.dat")) {
// 写入字符串数据
String text = "Hello, Java IO!";
byte
