Java的New Input/Output (NIO)库是一种非阻塞I/O操作的集合,旨在提高I/O操作的效率。相比于传统的Java I/O(基于java.io包),NIO提供了更灵活、更强大的I/O处理能力。以下是一篇详细的文章,帮助你彻底熟练掌握并使用Java的NIO操作。
一、Java NIO概述
Java NIO(New I/O)主要包含以下几个核心组件:
Channels(通道):用于数据的读写操作,是NIO的核心组件之一。常见的通道类型有:
FileChannel:用于文件读写。
SocketChannel:用于网络客户端的读写。
ServerSocketChannel:用于网络服务器的读写。
DatagramChannel:用于无连接的UDP通信。
Pipe.SourceChannel 和 Pipe.SinkChannel:用于线程间的管道通信。
Buffers(缓冲区):用于临时存储数据。缓冲区是一个字节容器,并提供了一组方法来操作这些字节。常见的缓冲区类型有:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
Selectors(选择器):用于管理多个Channel,并可以检测哪些Channel可以进行读、写、连接等I/O操作。
二、Buffers(缓冲区)详解
- 缓冲区的创建
java
ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配一个容量为1024字节的缓冲区 - 缓冲区的操作
写数据:
java
buffer.put((byte) 10);
buffer.put(new byte[]{1, 2, 3, 4});
buffer.put(new byte[5], 1, 3); // 从索引1开始,复制3个字节
切换读写模式:
在写数据之后,需要切换到读模式:
java
buffer.flip();
读数据:
java
while (buffer.hasRemaining()) {
byte b = buffer.get();
System.out.println(b);
}
重置缓冲区:
java
buffer.clear(); // 准备再次写数据
标记和重置:
java
buffer.mark();
buffer.position(5);
buffer.reset(); // 重置到标记的位置
三、Channels(通道)详解
- FileChannel
java
RandomAccessFile file = new RandomAccessFile("example.txt", "rw");
FileChannel fileChannel = file.getChannel();
// 写数据到文件
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("Hello NIO".getBytes());
buffer.flip();
fileChannel.write(buffer);
// 读数据从文件
buffer.clear();
fileChannel.read(buffer);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
http://yim6.5hai.com/
fileChannel.close();
file.close();
2. SocketChannel 和 ServerSocketChannel
客户端:
java
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 8080));
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("Hello Server".getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
socketChannel.read(buffer);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
socketChannel.close();
服务器:
java
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
socketChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
buffer.put("Hello Client".getBytes());
buffer.flip();
socketChannel.write(buffer);
socketChannel.close();
}
}
四、Selectors(选择器)详解
选择器允许一个单独的线程管理多个通道(Channel),并且能够知道哪些通道可以进行I/O操作。
http://yim7.5hai.com/
java
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // 阻塞直到至少有一个通道准备好
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.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);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
client.close();
}
keyIterator.remove();
}
}
五、总结
Java NIO提供了一种高效、灵活的方式来处理I/O操作。通过理解并使用Buffers、Channels和Selectors,可以编写出高并发、高性能的网络应用程序。掌握NIO的关键在于理解其非阻塞的特性和事件驱动的设计模式。希望这篇文章能帮助你彻底掌握Java的NIO操作。