Java NIO之Scatter和Gather

avatar
Android @奇舞团Android团队

前面的文章分享了Buffer和Channel,以及关于Buffer和Channel的基本操作。这篇文章继续分享关于Channel的Buffer的操作Scatter和Gather,这篇内容比较简单。

什么是Scatter和Gather

Scatter和Gather的字面意思就可以分好的解释他们各自的用途。其中Scatter的意思是分散,Gather的意思是聚集,我们再来看一下他们是如何分散和聚集的,如下图所示

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/12/12/167a0124c7b94db2~tplv-t2oaga2asx-image.image

当一个Channel中的数据被多个Buffer来处理,就是分散也就是Scatter。

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/12/12/167a0124c7cce270~tplv-t2oaga2asx-image.image

当多个Buffer同时向一个Channel中写数据时,就是聚集也就是Gather。

如何使用

我们用FileChannel来解释如何使用Scatter和Gather。

Gather

RandomAccessFile randomAccessFile = new RandomAccessFile(
		"/Users/yangpeng/Documents/360/code/QiwooSample/NIOSample/src/com/nio/sample/file.txt", "rw");
randomAccessFile.seek(0);

FileChannel fileChannel = randomAccessFile.getChannel();
System.out.println("FileChannel position " + fileChannel.position());

ByteBuffer buffer = ByteBuffer.allocate(100);
String str = "hello";
buffer.clear();
buffer.put(str.getBytes());
buffer.flip();

ByteBuffer buffer2 = ByteBuffer.allocate(100);
String str2 = " world";
buffer2.clear();
buffer2.put(str2.getBytes());
buffer2.flip();

ByteBuffer[] bufferArray = { buffer, buffer2 };
fileChannel.write(bufferArray);

randomAccessFile.close();
fileChannel.close();

  • 通过RandomAccessFile获得一个FileChannel
  • 分别初始化两个ByteBuffer,里面分别放入"hello"和"world"两个字符串。
  • 初始化一个ByteBuffer数组,内容为第二步的两个Buffer
  • 把ByteBuffer数组里的内容写入到FileChannel
  • 关闭RandomAccessFile和FileChannel

执行完以上几步之后,我们打开文件查看就是文本里的内容就是"hello world"

注意:写入的是缓冲区position和limit之间的数据。如果一个缓冲区容量为10字节,但是仅有5字节的数据,那么写入到通道中的数据就是5个字节。

Scatter

RandomAccessFile randomAccessFile = new RandomAccessFile(
		"/Users/yangpeng/Documents/360/code/QiwooSample/NIOSample/src/com/nio/sample/file.txt", "rw");
randomAccessFile.seek(0);

FileChannel fileChannel = randomAccessFile.getChannel();

ByteBuffer buffer = ByteBuffer.allocate(5);

ByteBuffer buffer2 = ByteBuffer.allocate(100);

ByteBuffer[] bufferArray = {buffer, buffer2};

fileChannel.read(bufferArray);

buffer.flip();
while (buffer.hasRemaining()) {
	System.out.print((char) buffer.get());
}

System.out.println("");

buffer2.flip();
while (buffer2.hasRemaining()) {
	System.out.print((char) buffer2.get());
}

randomAccessFile.close();
fileChannel.close();
  • 通过RandomAccessFile获得一个FileChannel
  • 分别初始化两个ByteBuffer,准备把数据读到这两个buffer里
  • 初始化一个ByteBuffer数组,内容为第二步的两个Buffer
  • 从FileChannel中读出数据然后写入到ByteBuffer中
  • 关闭RandomAccessFile和FileChannel

执行完以上几步之后,输出的内容就是"hello world"

注意:read()方法根据缓冲区数组中的顺序将channel数据写入。一个缓冲区写满后,再往下一个缓冲区写。

使用场景

适用于写入或者读出的数据是固定大小的几部分。

关注微信公众号,最新技术干货实时推送

image