Java I/O Stream
1. 概念
- Stream 是 Java I/O 系统中的基本概念,用于处理数据的输入和输出。Stream 提供了处理原始字节或字符的方式,常用于文件读写、数据流传输等操作。
2. 分类
-
字节流(Byte Streams): 用于处理原始二进制数据。常用的类有
InputStream
和OutputStream
及其子类,如FileInputStream
、FileOutputStream
。 -
字符流(Character Streams): 用于处理字符数据,适合于文本文件的读写。常用的类有
Reader
和Writer
及其子类,如FileReader
、FileWriter
。
3. 特点
-
阻塞 I/O: 默认情况下,Stream 操作是阻塞的,即调用 I/O 操作的方法时,线程会被阻塞直到操作完成。例如,
read()
方法在数据可用时才会返回。 -
简单易用: Stream 提供了直观的 API,易于实现简单的 I/O 操作。例如,读取文件的每一行,使用
BufferedReader
就可以很方便地实现。 -
装饰者模式: Stream 使用装饰者模式增强功能。例如,
BufferedReader
用于提供缓冲功能,PrintWriter
用于格式化输出。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class StreamExample {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java NIO Channel
1. 概念
- Channel 是 Java NIO (New I/O) 提供的一种机制,用于实现更高效的 I/O 操作。
Channel
提供了对异步和非阻塞 I/O 操作的支持。
2. 特点
-
非阻塞 I/O: Channel 支持异步和非阻塞 I/O 操作。通过
Selector
类,可以在一个线程中同时管理多个 Channel 的 I/O 操作,而不需要为每个 I/O 操作创建新的线程。这样可以显著提高系统的 I/O 处理能力。 -
直接缓冲区: NIO 提供了
ByteBuffer
直接操作操作系统的 I/O 缓冲区,减少了数据在内存中的拷贝,提高了性能。 -
选择器:
Selector
允许单线程处理多个 Channel 的 I/O 操作。通过select()
方法可以检测哪些 Channel 有事件发生(如可读、可写),适合处理大量并发的 I/O 操作。
3. 操作
-
读/写: 使用
read()
和write()
方法进行数据传输。ByteBuffer
是 Channel 操作的核心,用于在 Channel 和应用程序之间传输数据。 -
选择器: 使用
Selector
来轮询和管理多个 Channel 的 I/O 操作状态。这对于处理高并发的网络连接非常有效。
4. 示例
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.io.IOException;
public class ChannelExample {
public static void main(String[] args) {
try (FileChannel fileChannel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = fileChannel.read(buffer);
while (bytesRead != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
bytesRead = fileChannel.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
比较总结
-
用途:
- Stream: 适用于传统的 I/O 操作,特别是简单的文件和数据流处理。易于理解和使用,适合于单线程应用。
- Channel: 适用于需要高效的 I/O 操作和高并发的场景。它能够处理大规模的并发连接或数据流,支持非阻塞 I/O 和异步处理。
-
性能:
- Stream: 性能较低,适合简单的 I/O 操作。
- Channel: 性能更高,特别是在高并发场景下,通过非阻塞和异步操作可以显著提高 I/O 性能。
-
复杂度:
- Stream: 简单易用,但对高并发的支持较弱。
- Channel: 使用较复杂,但提供了更强大的功能和更高的性能,适合处理复杂的 I/O 需求。