Java NIO 内置了 Scatter(分散器) 和 Gather(聚集器),Scatter 和 Gather 是从 Channel 中读取数据或者向 Channel 中写入数据的相关概念。
Channel 的分散(Scatter)读是指将一个 Channel 中的数据读取到多个 Buffer 中的读操作,即将这个 Channel 中的数据“分散”到多个 Buffer 中。
Channel 的聚集(Gather)写指的是将多个 Buffer 中的数据写入到一个 Channel 中的写操作,即这个 Channel “聚集”了来自多个 Buffer 的数据。
在需要分别处理传输数据的各个部分的情况下,Scatter 和 Gather 是非常有用的。比如说,一个消息(message)由消息头(header)和消息体(body)组成,就可以将消息头和消息体分别放在两个独立的 Buffer 中,这样做可以分开处理消息头和消息体,会更简便。
1、分散读(Scattering Reads)
“分散读”是从一个 Channel 中向多个 Buffer 中读数据,如下图所示:
代码示例如下:
RandomAccessFile raf = new RandomAccessFile("F:\\temp\\file.txt", "rw");
FileChannel channel = raf.getChannel();
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
header.put("header".getBytes());
body.put("body".getBytes());
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
raf.close();
注意
:Buffers 首先插入到一个数组中,然后将这个数组作为 Channel.read() 方法的入参传入,read() 方法将按照 Buffer 在数组中的顺序将从 Channel 中读取的数据写入到这些 Buffer 中。只有当前面的 Buffer 被写满后,Channel 才会向后一个 Buffer 中写数据。既然只有前面的 Buffer 写满后才会向后面的 Buffer 中写数据,也就意味着这不适合那些长度是动态变化的消息的读取(比如消息的消息头长度不固定)。
2、聚集写(Gathering Writes)
聚集写是将多个 Buffer 中的数据写入到一个 Channel 中,如下图所示:
代码示例如下:
RandomAccessFile raf = new RandomAccessFile("F:\\temp\\file.txt", "rw");
FileChannel channel = raf.getChannel();
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
header.put("header".getBytes());
body.put("body".getBytes());
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);
raf.close();
Buffer 的数组作为入参传递给 Channel.write() 方法,write() 方法会按照 Buffer 在数组中的位置将 Buffer 中的数据内容写入到 Channel 中,注意只会写入 Buffer 中在 position 和 limit 之间的数据。因此与“分散读”不同,“聚集写”可以很好的处理长度不固定的动态消息。