Java-IO、NIO
Java IO 和 NIO 介绍
Java 提供了两种主要的 I/O 模型:IO(Blocking I/O) 和 NIO(Non-blocking I/O)。它们分别适用于不同的场景,理解它们的区别和使用方法对于编写高效的 Java 程序非常重要。
一、Java IO(Blocking I/O)
1. 特点
- 阻塞式:当线程执行读/写操作时,如果数据没有准备好,线程会一直阻塞,直到数据就绪。
- 流式模型:基于流(Stream)的 I/O,数据像水流一样单向流动。
- 面向字节/字符:
- 字节流:
InputStream
和OutputStream
。 - 字符流:
Reader
和Writer
。
- 字节流:
2. 核心类
- 字节流:
FileInputStream
/FileOutputStream
:文件读写。BufferedInputStream
/BufferedOutputStream
:带缓冲区的字节流。
- 字符流:
FileReader
/FileWriter
:文件读写。BufferedReader
/BufferedWriter
:带缓冲区的字符流。
3. 示例
// 使用字节流读取文件
try (FileInputStream fis = new FileInputStream("input.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
int data;
while ((data = bis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 使用字符流读取文件
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
4. 适用场景
- 简单的文件读写。
- 数据量较小、并发要求不高的场景。
二、Java NIO(Non-blocking I/O)
1. 特点
- 非阻塞式:线程在读写数据时不会被阻塞,可以处理其他任务。
- 缓冲区模型:数据先读写到缓冲区(Buffer),再进行处理。
- 通道(Channel):用于连接数据源和目标,支持双向读写。
- 选择器(Selector):用于监听多个通道的事件(如连接、读写)。
2. 核心类
- Buffer:
ByteBuffer
、CharBuffer
、IntBuffer
等。
- Channel:
FileChannel
:文件读写。SocketChannel
、ServerSocketChannel
:网络通信。DatagramChannel
:UDP 通信。
- Selector:
- 用于监听多个通道的事件。
3. 示例
// 使用 NIO 读取文件
try (FileChannel channel = FileChannel.open(Paths.get("input.txt"))) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channel.read(buffer) != -1) {
buffer.flip(); // 切换为读模式
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear(); // 清空缓冲区,准备下一次读取
}
} catch (IOException e) {
e.printStackTrace();
}
// 使用 NIO 实现非阻塞网络通信
try (Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open()) {
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
// 处理连接事件
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 处理读事件
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
clientChannel.read(buffer);
buffer.flip();
System.out.println(new String(buffer.array(), 0, buffer.limit()));
buffer.clear();
}
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
4. 适用场景
- 高并发、高吞吐量的网络通信。
- 需要非阻塞 I/O 的场景(如聊天服务器、文件服务器)。
三、Java IO 和 NIO 的区别
特性 | Java IO | Java NIO |
---|---|---|
模型 | 阻塞式 | 非阻塞式 |
数据流 | 单向流(Stream) | 双向通道(Channel) |
缓冲区 | 无缓冲区 | 基于缓冲区(Buffer) |
多路复用 | 不支持 | 支持(Selector) |
适用场景 | 简单文件读写、低并发场景 | 高并发、高吞吐量场景 |
四、Java NIO 的高级特性
1. 内存映射文件(Memory-Mapped File)
- 将文件直接映射到内存中,避免频繁的系统调用。
- 示例:
try (FileChannel channel = FileChannel.open(Paths.get("input.txt"))) { MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } } catch (IOException e) { e.printStackTrace(); }
2. 分散(Scatter)和聚集(Gather)
- 分散:从单个通道读取数据到多个缓冲区。
- 聚集:将多个缓冲区的数据写入单个通道。
- 示例:
ByteBuffer header = ByteBuffer.allocate(128); ByteBuffer body = ByteBuffer.allocate(1024); ByteBuffer[] buffers = {header, body}; try (FileChannel channel = FileChannel.open(Paths.get("input.txt"))) { channel.read(buffers); // 分散读取 } catch (IOException e) { e.printStackTrace(); }
3. 文件锁(File Lock)
- 控制多个进程对同一文件的并发访问。
- 示例:
try (FileChannel channel = FileChannel.open(Paths.get("input.txt"), StandardOpenOption.WRITE)) { FileLock lock = channel.lock(); // 获取文件锁 // 执行写操作 lock.release(); // 释放文件锁 } catch (IOException e) { e.printStackTrace(); }
五、总结
- Java IO:
- 适用于简单的文件读写和低并发场景。
- 基于流模型,操作简单但性能较低。
- Java NIO:
- 适用于高并发、高吞吐量的场景。
- 基于缓冲区和通道模型,支持非阻塞 I/O 和多路复用。
根据实际需求选择合适的 I/O 模型:
- 如果需要处理高并发网络通信,选择 NIO。
- 如果只是简单的文件读写,选择 IO 即可。
通过掌握 Java IO 和 NIO 的使用方法,可以更好地应对不同的 I/O 需求,编写高效的 Java 程序。
播种和收获通常不在一个季节,而中间的过程叫做坚持~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2022-02-21 Java中的泛型
2020-02-21 shell脚本自动化部署