通常,NIO中的所有IO都以Channel开头,数据可以从Channel
读入Buffer
,也可以从Buffer
写入Channel
。
以下是NIO中Channel
实现类的列表,这些通道包括UDP+TCP网络IO和文件IO:
ServerSocketChannel
:服务器套接字通道
以下是 NIO 中的核心 Buffer 实现,其实就是 7 种基本类型:
Channel(通道)
NIO 中的通道类似于流,单丝两者之间存在一些区别:
// 文件内容 123456789
RandomAccessFile accessFile = new RandomAccessFile("D:\\test.txt", "rw");
FileChannel fileChannel = accessFile.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(48);
// 将数据从Channel读取到Buffer中,返回读取的字节数
int data = fileChannel.read(buffer);
Buffer(缓冲区)
使用Buffer
读取和写入数据通常遵循以下四个步骤:
调用buffer.clear()
或者buffer.compact()
清除缓冲区内容。
RandomAccessFile accessFile = new RandomAccessFile("D:\\test.txt", "rw");
FileChannel fileChannel = accessFile.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(48);
// 将数据从Channel读取到Buffer中,返回读取的字节数
int data = fileChannel.read(buffer);
while(data != -1) {
System.out.println("Read " + data);
// 将Buffer从写模式切换到读模式
buffer.flip();
while(buffer.hasRemaining()) {
// 每次读取1byte,循环输出 123456789
System.out.println((char) buffer.get());
}
// 清空Buffer,将Buffer从读模式切换到写模式
buffer.clear();
data = fileChannel.read(buffer);
}
accessFile.close();java
Channel 通道只负责传输数据、不直接操作数据。操作数据都是通过Buffer缓冲区进行的。通常,通道可以分为两大类:文件通道和套接字通道,
FileChannel:用于文件IO的通道,支持文件的读写等操作。FileChannel允许在文件的任意位置进行数据传输,支持文件锁定以及内存映射文件等高级功能。FileChannel无法设置为非阻塞模式,因为它只适用于阻塞式文件操作。 SocketChannel:用于TCP套接字的IO通信。SocketChannel支持非阻塞模式,可以与Selector一起使用,实现高效的网络通信。Socket Channel允许连接到远程主机,进行数据传输。 与之匹配的有ServerSocketChannel:用于坚挺TCP套接字连接的通道。与SocketChannel类似,ServerSocketChannel也支持非阻塞模式,并可以与Selector一起使用。 DatagramChannel:用于UDP套接字IO通道,支持非阻塞
FileChannel
FileChannel.open(Paths.get("docs/配套教程.md"), StandardOpenOption.WRITE);
使用FileChannel 配合 ByteBuffer 缓冲区实现文件复制的功能:
try (FileChannel sourceChannel = FileChannel.open(Paths.get("logs/javabetter/itwanger.txt"), StandardOpenOption.READ);
FileChannel destinationChannel = FileChannel.open(Paths.get("logs/javabetter/itwanger1.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (sourceChannel.read(buffer) != -1) {
buffer.flip();
destinationChannel.write(buffer);
buffer.clear();
}
}
使用内存映射文件(MappedByteBuffer)的方式实现文件复制的功能(直接操作缓冲区):
try (FileChannel sourceChannel = FileChannel.open(Paths.get("logs/javabetter/itwanger.txt"), StandardOpenOption.READ);
FileChannel destinationChannel = FileChannel.open(Paths.get("logs/javabetter/itwanger2.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.READ)) {
long fileSize = sourceChannel.size();
MappedByteBuffer sourceMappedBuffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
MappedByteBuffer destinationMappedBuffer = destinationChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);
for (int i = 0; i < fileSize; i++) {
byte b = sourceMappedBuffer.get(i);
destinationMappedBuffer.put(i, b);
}
}
通道之间通过transfer()实现数据的传输(直接操作缓冲区):
try (FileChannel sourceChannel = FileChannel.open(Paths.get("logs/javabetter/itwanger.txt"), StandardOpenOption.READ);
FileChannel destinationChannel = FileChannel.open(Paths.get("logs/javabetter/itwanger3.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.READ)) {
sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
} catch (IOException e) {
throw new RuntimeException(e);
}