IO流学习
思维图
在Java中,流是用来处理输入输出的一种机制。流的顶层父类为输入输出操作定义了一个框架,以下是关于这些顶层父类的详细信息:
Java流顶层父类概述
一、IO 流的分类
1. 按数据流向(这里理解一下)****输出流为我输出给电脑output即为OutputStream
- 输入流:从(文件)外部(如文件、网络)读取数据到程序。
- 示例:
InputStream
,Reader
- 示例:
- 输出流:从程序写出数据到文件或者其他。
- 示例:
OutputStream
,Writer
- 示例:
2. 按数据类型
- 字节流:以 字节(8位) 为单位处理数据,适合所有类型文件(如图片、视频)。
- 核心类:
InputStream
、OutputStream
- 核心类:
- 字符流:以 字符(16位,基于编码) 为单位处理数据,适合文本文件。(中文)
- 核心类:
Reader
、Writer
- 核心类:
3. 按功能
- 节点流:直接操作数据源(如文件)。
- 示例:
FileInputStream
,FileReader
- 示例:
- 处理流(装饰流):对现有流封装,增强功能(如缓冲、转换)。
- 示例:
BufferedInputStream
,InputStreamReader
- 这里的装饰理解为将字节装饰为字符
- 示例:
InputStream 和 OutputStream
- InputStream:这是所有字节输入流的超类。它定义了读取数据的基本方法,比如从输入流中读取字节和字节数组。
- 方法:
int read()
: 从输入流中读取下一个字节的数据。int read(byte[] b)
: 从输入流中读取一些字节,并将它们存储到指定的字节数组中。void close()
: 关闭输入流,并释放与该流关联的所有系统资源。
- OutputStream:这是所有字节输出流的超类。它定义了写入数据的基本方法,比如将字节和字节数组写入输出流。
- 方法:
void write(int b)
: 将指定的字节写入输出流。void write(byte[] b)
: 将指定的字节数组写入输出流。void flush()
: 刷新输出流,并强制写出所有缓冲的输出字节。void close()
: 关闭输出流,并释放与该流关联的所有系统资源。
Reader 和 Writer
- Reader:这是所有字符输入流的超类。它扩展了
InputStreamReader
,用于读取字符数据。 - 方法:
int read()
: 读取单个字符。int read(char[] cbuf)
: 读取字符到一个数组中。void close()
: 关闭流并释放资源。
- Writer:这是所有字符输出流的超类。它用于写入字符数据。
- 方法:
void write(int c)
: 写入单个字符。void write(char[] cbuf)
: 写入字符数组。void write(String str)
: 写入字符串。void flush()
: 刷新流。void close()
: 关闭流并释放资源。
以下是一个简单的表格总结:
流类型 | 简介 |
---|---|
字节流**** | 以字节为单位进行数据的输入输出,适用于所有类型的数据**。** |
FileInputStream | 常用的文件输入流,用于从文件中读取数据。 |
FileOutputStream | 常用的文件输出流,用于向文件中写入数据。 |
字符流 | 以字符为单位进行数据的输入输出,通常用于文本数据。 |
FileReader | 用于读取字符文件,继承了 InputStreamReader。 |
FileWriter | 用于写入字符文件,继承了 OutputStreamWriter。 |
数组流 | 针对内存中的数据流进行操作,也称为内存流。 |
ByteArrayInputStream | 从内存中读取数据的输入流。 |
ByteArrayOutputStream | 向内存中写入数据的输出流。 |
管道流 | 用于线程之间的数据传递。 |
PipedInputStream | 管道输入流,用于从一个线程读取数据。 |
PipedOutputStream | 管道输出流,用于向另一个线程写入数据。 |
基本数据类型流 | 用于输入输出基本数据类型。 |
DataInputStream | 用于读取Java基本数据类型的数据。 |
DataOutputStream | 用于写入Java基本数据类型的数据。 |
缓冲流 | 提供缓冲机制,提高I/O效率。 |
BufferedInputStream | 带缓冲的字节输入流,提高读取效率。 |
BufferedOutputStream | 带缓冲的字节输出流,提高写入效率。 |
BufferedReader | 带缓冲的字符输入流,提高读取效率。 |
BufferedWriter | 带缓冲的字符输出流,提高写入效率。 |
打印流 | 用于格式化输出数据。 |
PrintStream | 打印流,可以打印数据到控制台或文件。 |
PrintWriter | 打印流,可以打印数据到控制台或文件,并支持格式化。 |
对象序列化/反序列化流 | 用于对象的序列化和反序列化。 |
ObjectOutputStream | 用于将对象序列化到输出流中。 |
ObjectInputStream | 用于从输入流中反序列化对象。 |
转换流 | 用于字节流和字符流之间的转换。 |
InputStreamReader | 用于将字节流转换为字符流。 |
OutputStreamWriter | 用于将字符流转换为字节流。 |
其他 | 其他特殊用途的流。 |
RandomAccessFile | 可以对文件进行随机访问的类,支持文件的读写操作。 |
1.什么是流 (Stream)?
一般来说关于流的特性有下面几点:
- 先进先出:最先写入输出流的数据最先被输入流读取到。
- 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile除外)
- 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。
二、核心类与用法
1. 字节流(Byte Streams)
- 读取文件:
FileInputStream
try (InputStream is = new FileInputStream("test.txt")) {
int data;
while ((data = is.read()) != -1) { // 逐字节读取
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
- 写入文件:
FileOutputStream
try (OutputStream os = new FileOutputStream("output.txt")) {
String text = "Hello, IO Stream!";
os.write(text.getBytes()); // 字节数组写入
} catch (IOException e) {
e.printStackTrace();
}
2. 字符流(Character Streams)
- 读取文本文件:
FileReader
+BufferedReader
try (Reader reader = new FileReader("test.txt");
BufferedReader br = new BufferedReader(reader)) {
String line;
while ((line = br.readLine()) != null) { // 逐行读取
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
- 写入文本文件:
FileWriter
+BufferedWriter
try (Writer writer = new FileWriter("output.txt");
BufferedWriter bw = new BufferedWriter(writer)) {
bw.write("Hello, 字符流!");
bw.newLine(); // 写入换行符
} catch (IOException e) {
e.printStackTrace();
}
3. 缓冲流(Buffered Streams)
- 提升IO效率,减少频繁读写磁盘次数。
// 字节缓冲流
try (InputStream is = new BufferedInputStream(new FileInputStream("largefile.bin"));
OutputStream os = new BufferedOutputStream(new FileOutputStream("copy.bin"))) {
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
}
// 字符缓冲流
try (BufferedReader br = new BufferedReader(new FileReader("text.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"))) {
// 逐行读写
}
4. 转换流(字节 ↔ 字符)
- 解决字节流与字符流的转换,指定编码(如UTF-8)。
// 字节流 → 字符流(按UTF-8读取)
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream("data.txt"), StandardCharsets.UTF_8)) {
// 使用字符流操作
}
// 字符流 → 字节流(按GBK写入)
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("data.txt"), "GBK")) {
osw.write("中文内容");
}
三、Java NIO(New IO)****这里是AI生成不理解后续慢慢学习
Java 1.4 引入的 NIO
(java.nio
包),支持非阻塞IO和通道(Channel)模型,适合高并发场景。
核心组件
- Buffer:数据容器(如
ByteBuffer
)。 - Channel:双向数据传输通道(如
FileChannel
,SocketChannel
)。 - Selector:多路复用,监控多个通道的事件。
示例:文件复制(NIO)
try (FileChannel src = FileChannel.open(Paths.get("src.txt"), StandardOpenOption.READ);
FileChannel dest = FileChannel.open(Paths.get("dest.txt"),
StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (src.read(buffer) != -1) {
buffer.flip(); // 切换为读模式
dest.write(buffer);
buffer.clear(); // 清空缓冲区,切换为写模式
}
}
四、最佳实践与常见问题
- 始终关闭流:
- 使用 try-with-resources(Java 7+)自动关闭资源,避免内存泄漏。
try (InputStream is = new FileInputStream("file.txt")) {
// 操作流
} // 自动调用 is.close()
- 选择正确的流类型:
- 文本文件 → 字符流(避免乱码)。
- 二进制文件(如图片) → 字节流。
- 优先使用缓冲流:
- 减少IO次数,显著提升性能(尤其是大文件)。
- 处理大文件:
- 分块读写(如
byte[8192]
),避免一次性加载到内存。
- 分块读写(如
- 编码问题:
- 明确指定字符编码(如
StandardCharsets.UTF_8
),避免跨平台乱码。
- 明确指定字符编码(如
五、总结对比
类别 | 字节流 | 字符流 | NIO |
---|---|---|---|
数据单位 | 字节(8位) | 字符(16位,带编码) | 块(Buffer) |
核心类 | InputStream /OutputStream | Reader /Writer | Channel /Buffer |
适用场景 | 图片、视频等二进制文件 | 文本文件 | 高并发、非阻塞IO |
性能优化 | 缓冲流(如 BufferedInputStream ) | 缓冲流(如 BufferedReader ) | 基于缓冲区和通道 |
掌握 IO 流是 Java 开发的基础技能,合理选择流类型和优化方式,可以大幅提升程序效率和稳定性!