Java NIO 学习笔记(七)----NIO/IO 的对比和总结

 目录:

有几种 Channel 和 Buffer ,以下是 NIO 中主要 Channel 实现类的列表,这些通道包括 UDP + TCP 网络 IO 和文件 IO:

这些类也有一些有趣的接口,但为了简单起见,这里暂时不提,后续会进行学习的。

以下是 NIO 中的核心 Buffer 实现,其实就是 7 种基本类型:

NIO 还有一个 MappedByteBuffer,它与内存映射文件一起使用,同样这个后续再讲。

Selectors 选择器

选择器允许单个线程处理多个通道。 如果程序打开了许多连接(通道),但每个连接只有较低的流量,使用选择器就很方便。 例如,在聊天服务器中, 以下是使用 Selector 处理 3 个 Channel 的线程图示:
1个线程使用选择器处理3个通道

要使用选择器,需要使用它注册通道。 然后你调用它的 select() 方法。 此方法将阻塞,直到有一个已注册通道的事件准备就绪。 一旦该方法返回,该线程就可以处理这些事件。 事件可以是传入连接,接收数据等。

Channel (通道)

NIO 通道类似于流,但有一些区别:

如上所述,NIO 中总是将数据从通道读取到缓冲区,或将数据从缓冲区写入通道。 这是一个例子:

// 文件内容是 123456789 RandomAccessFile accessFile = new RandomAccessFile("D:\\test\\1.txt", "rw"); FileChannel fileChannel = accessFile.getChannel();  ByteBuffer buffer = ByteBuffer.allocate(48);  int data = fileChannel.read(buffer); // 将 Channel 的数据读入缓冲区,返回读入到缓冲区的字节数

Buffer(缓冲区)

使用 Buffer 与 Channel 交互,数据从通道读入缓冲区,或从缓冲区写入通道。
缓冲区本质上是一个可以写入数据的内存块,之后可以读取数据。 Buffer 对象包装了此内存块,提供了一组方法,可以更轻松地使用内存块。

Buffer 的基本用法

使用 Buffer 读取和写入数据通常遵循以下四个步骤:

  1. 将数据写入缓冲区
  2. 调用 buffer.flip() 反转读写模式
  3. 从缓冲区读取数据
  4. 调用 buffer.clear() 或 buffer.compact() 清除缓冲区内容

将数据写入Buffer 时,Buffer 会跟踪写入的数据量。 当需要读取数据时,就使用 flip() 方法将缓冲区从写入模式切换到读取模式。 在读取模式下,缓冲区允许读取写入缓冲区的所有数据。

读完所有数据之后,就需要清除缓冲区,以便再次写入。 可以通过两种方式执行此操作:通过调用 clear() 或调用 compact() 。区别在于 clear() 是方法清除整个缓冲区,而 compact() 方法仅清除已读取的数据,未读数据都会移动到缓冲区的开头,新数据将在未读数据之后写入缓冲区。

这是一个简单的缓冲区用法示例:

public class ChannelExample {     public static void main(String[] args) throws IOException {     // 文件内容是 123456789         RandomAccessFile accessFile = new RandomAccessFile("D:\\test\\1.txt", "rw");         FileChannel fileChannel = accessFile.getChannel();          ByteBuffer buffer = ByteBuffer.allocate(48); //创建容量为48字节的缓冲区          int data = fileChannel.read(buffer); // 将 Channel 的数据读入缓冲区,返回读入到缓冲区的字节数         while (data != -1) {             System.out.println("Read " + data); // Read 9             buffer.flip(); // 将 buffer 从写入模式切换为读取模式             while (buffer.hasRemaining()) {                 System.out.print((char) buffer.get()); // 每次读取1byte,循环输出 123456789             }             buffer.clear(); // 清除当前缓冲区             data = fileChannel.read(buffer); // 将 Channel 的数据读入缓冲区         }         accessFile.close();     } }
Buffer 的 capacity,position 和 limit

缓冲区有 3 个需要熟悉的属性,以便了解缓冲区的工作原理。 这些是:

  1. 关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信