java.nio
(New I/O)是 Java 1.4 引入的高性能 I/O API,提供了比传统 java.io
更高效的 I/O 操作方式,特别适合处理大量数据和高并发场景。
核心组件
1. 缓冲区(Buffers)
核心类:
-
ByteBuffer
、CharBuffer
、ShortBuffer
、IntBuffer
、LongBuffer
、FloatBuffer
、DoubleBuffer
-
MappedByteBuffer
(内存映射文件缓冲区)
基本用法:
java
// 创建缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024); // 堆缓冲区
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); // 直接缓冲区
// 写入数据
buffer.put((byte)1);
buffer.putInt(123);
buffer.putDouble(3.14);
// 切换为读模式
buffer.flip();
// 读取数据
byte b = buffer.get();
int i = buffer.getInt();
double d = buffer.getDouble();
// 清空缓冲区
buffer.clear();
缓冲区状态属性:
-
capacity:缓冲区容量
-
position:当前位置
-
limit:读写限制
-
mark:标记位置
2. 通道(Channels)
核心通道类:
-
FileChannel
:文件通道 -
SocketChannel
、ServerSocketChannel
:TCP 通道 -
DatagramChannel
:UDP 通道 -
Pipe.SinkChannel
、Pipe.SourceChannel
:管道通道
文件通道示例:
java
// 文件读取
try (FileChannel channel = FileChannel.open(Paths.get("file.txt"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channel.read(buffer) > 0) {
buffer.flip();
// 处理数据
buffer.clear();
}
}
// 文件写入
try (FileChannel channel = FileChannel.open(Paths.get("file.txt"),
StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
ByteBuffer buffer = ByteBuffer.wrap("Hello NIO".getBytes());
channel.write(buffer);
}
3. 选择器(Selectors)
用于非阻塞 I/O 的多路复用:
java
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
// 处理新连接
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 处理读取
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
client.read(buffer);
// 处理数据
}
iter.remove();
}
}
高级特性
1. 内存映射文件(Memory-Mapped Files)
java
try (FileChannel channel = FileChannel.open(Paths.get("largefile.dat"),
StandardOpenOption.READ)) {
MappedByteBuffer mappedBuffer = channel.map(
FileChannel.MapMode.READ_ONLY, 0, channel.size());
// 直接操作内存映射区域
while (mappedBuffer.hasRemaining()) {
byte b = mappedBuffer.get();
}
}
2. 文件锁定
java
try (FileChannel channel = FileChannel.open(Paths.get("file.txt"),
StandardOpenOption.WRITE)) {
// 排他锁
FileLock lock = channel.lock();
try {
// 执行写操作
channel.write(ByteBuffer.wrap("Data".getBytes()));
} finally {
lock.release();
}
// 共享锁(只读)
FileLock sharedLock = channel.lock(0, Long.MAX_VALUE, true);
}
3. 分散/聚集 I/O(Scatter/Gather)
java
// 分散读取
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] buffers = {header, body};
channel.read(buffers);
// 聚集写入
header.flip();
body.flip();
channel.write(buffers);
4. 文件系统操作
java.nio.file
包(NIO.2,Java 7 引入)提供了更强大的文件系统操作:
java
Path path = Paths.get("/path/to/file");
Files.createDirectories(path.getParent());
Files.write(path, "content".getBytes(), StandardOpenOption.CREATE);
// 遍历目录
try (Stream<Path> stream = Files.list(Paths.get("/tmp"))) {
stream.forEach(System.out::println);
}
// 文件监控
WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Paths.get("/path/to/watch");
dir.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
性能优势
-
非阻塞 I/O:允许单线程管理多个通道
-
内存映射:直接操作文件内存映射,避免系统调用
-
直接缓冲区:减少 JVM 堆与本地内存间的数据拷贝
-
零拷贝 :通过
FileChannel.transferTo/transferFrom
实现
与传统 I/O 对比
特性 | java.io | java.nio |
---|---|---|
数据流 | 流式 | 基于缓冲区 |
阻塞模式 | 阻塞 | 可选非阻塞 |
多连接处理 | 每个连接一个线程 | 单线程多路复用 |
性能 | 适合少量连接 | 适合高并发 |
API 复杂度 | 简单 | 较复杂 |
最佳实践
-
大文件处理:优先使用内存映射文件
-
高并发网络:使用 Selector 实现非阻塞 I/O
-
频繁 I/O 操作:使用直接缓冲区减少拷贝
-
资源释放:确保关闭通道和选择器
-
异常处理 :妥善处理
IOException
和ClosedChannelException
总结
java.nio
包提供了:
-
基于缓冲区的 I/O 操作
-
非阻塞 I/O 支持
-
内存映射文件功能
-
高效的文件和网络操作
-
更灵活的文件系统接口(NIO.2)
虽然学习曲线比传统 I/O 更陡峭,但在处理高性能 I/O 需求时,NIO 通常是更好的选择。对于简单文件操作,可以结合使用 java.nio.file
包提供的便捷方法。