转自:http://blog.youkuaiyun.com/java2000_wl/article/details/7619395
1.Scatter 从一个Channel读取的信息分散到N个缓冲区中(Buufer).
2.Gather 将N个Buffer里面内容按照顺序发送到一个Channel.
Scatter/Gather功能是通道(Channel)提供的 并不是Buffer,
Scatter/Gather相关接口 类图
ReadableByteChannel WritableByteChannel 接口提供了通道的读写功能
ScatteringByteChannel GatheringByteChannel接口都新增了两个以缓冲区数组作为参数的相应方法
以FileChannel为例
*Scatter
package com.zhilong.nio.example;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
public class ScatterGatherTest {
private static Charset charset = Charset.forName("GBK");
/**
* Scatter
* <br>------------------------------<br>
* @param fileName
* @throws IOException
* @see FileChannel.read(java.nio.ByteBuffer[])
*/
private static void scatter(final String fileName) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile(fileName, "r");
//获取文件通道
FileChannel channel = accessFile.getChannel();
//创建两个缓冲区
ByteBuffer headBuffer = ByteBuffer.allocate(2);
ByteBuffer bodyBuffer = ByteBuffer.allocate(1024);
ByteBuffer[] allBuffers = new ByteBuffer[]{headBuffer, bodyBuffer};
// headBuffer 前10个字节
// bodyBuffer 剩下的
long n = channel.read(allBuffers);
System.out.println("共读到多少字节:" + n);
headBuffer.flip();
//head缓冲区中的数据:qw
System.out.println("head缓冲区中的数据:" + charset.decode(headBuffer));
bodyBuffer.flip();
//body缓冲区中的数据:ertyuiop
System.out.println("body缓冲区中的数据:" + charset.decode(bodyBuffer));
accessFile.close();
channel.close();
}
/**
* Scatter2
* <br>------------------------------<br>
* @param fileName
* @throws IOException
* @see FileChannel.read(java.nio.ByteBuffer[], int, int)
*/
private static void scatter2(final String fileName) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile(fileName, "r");
//获取文件通道
FileChannel channel = accessFile.getChannel();
//创建五个缓冲区
ByteBuffer headBuffer = ByteBuffer.allocate(2);
ByteBuffer bodyBuffer1 = ByteBuffer.allocate(3);
ByteBuffer bodyBuffer2 = ByteBuffer.allocate(2);
ByteBuffer bodyBuffer3 = ByteBuffer.allocate(2);
ByteBuffer bodyBuffer4 = ByteBuffer.allocate(1);
ByteBuffer[] allBuffers = new ByteBuffer[]{
headBuffer,
bodyBuffer1, bodyBuffer2,
bodyBuffer3, bodyBuffer4,};
//0从那个缓冲区开始被使用 使用3个缓冲区
//会使用 headBuffer,bodyBuffer1,bodyBuffer2
long n = channel.read(allBuffers, 0, 3);
System.out.println("共读到多少字节:" + n);
headBuffer.flip();
//head缓冲区中的数据:qw
System.out.println("head缓冲区中的数据:" + charset.decode(headBuffer));
bodyBuffer1.flip();
//body1缓冲区中的数据:ert
System.out.println("body1缓冲区中的数据:" + charset.decode(bodyBuffer1));
bodyBuffer2.flip();
//body2缓冲区中的数据:yu
System.out.println("body2缓冲区中的数据:" + charset.decode(bodyBuffer2));
bodyBuffer3.flip();
//body3,没有数据
System.out.println("body3缓冲区中的数据:" + charset.decode(bodyBuffer3));
bodyBuffer4.flip();
//body4没有数据
System.out.println("body4缓冲区中的数据:" + charset.decode(bodyBuffer4));
accessFile.close();
channel.close();
}
/**
*
* <br>------------------------------<br>
* @param fileName
* @throws IOException
*/
private static void writeData(final String fileName, String data) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile(fileName, "rw");
accessFile.writeBytes(data);
accessFile.close();
}
public static void main(String[] args) throws IOException {
final String fileName = "D:/test.log";
//先写入10个字节数据 以便测试 scatter模式
writeData(fileName, "qwertyuiop");
/**----------Scatter------------*/
//read(java.nio.ByteBuffer[])
scatter(fileName);
//read(java.nio.ByteBuffer[], int, int)
scatter2(fileName);
}
/**
* gather
* <br>------------------------------<br>
* @param fileName
* @throws IOException
* @see FileChannel#write(java.nio.ByteBuffer[])
*/
private static void gather(String fileName) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile(fileName, "rw");
//获取文件通道
FileChannel channel = accessFile.getChannel();
//创建两个缓冲区
ByteBuffer headBuffer = ByteBuffer.allocate(3);
headBuffer.put("abc".getBytes());
ByteBuffer bodyBuffer = ByteBuffer.allocate(1024);
bodyBuffer.put("defg".getBytes());
ByteBuffer[] allBuffers = new ByteBuffer[]{headBuffer, bodyBuffer};
headBuffer.flip();
bodyBuffer.flip();
//将按allBuffers顺序 写入abcdefg
long n = channel.write(allBuffers);
System.out.println("共写入多少字节:" + n);
accessFile.close();
channel.close();
}
/**
* gather2
* <br>------------------------------<br>
* @param fileName
* @throws IOException
* @see FileChannel#write(java.nio.ByteBuffer[], int, int)
*/
private static void gather2(String fileName) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile(fileName, "rw");
//获取文件通道
FileChannel channel = accessFile.getChannel();
//创建两个缓冲区
ByteBuffer headBuffer = ByteBuffer.allocate(3);
ByteBuffer bodyBuffer1 = ByteBuffer.allocate(4);
ByteBuffer bodyBuffer2 = ByteBuffer.allocate(20);
ByteBuffer bodyBuffer3 = ByteBuffer.allocate(20);
ByteBuffer bodyBuffer4 = ByteBuffer.allocate(20);
headBuffer.put("abc".getBytes());
bodyBuffer1.put("defg".getBytes());
bodyBuffer2.put("bnbnbnb".getBytes());
bodyBuffer3.put("zzz444".getBytes());
ByteBuffer[] allBuffers = new ByteBuffer[]{
headBuffer,
bodyBuffer1, bodyBuffer2,
bodyBuffer3, bodyBuffer4,};
headBuffer.flip();
bodyBuffer1.flip();
bodyBuffer2.flip();
bodyBuffer3.flip();
bodyBuffer4.flip();
//将按allBuffers数组顺序使用两个缓冲区
//0从哪开始
//2使用几个
//当前使用headBuffer bodyBuffer1
//最终写入abcdefg
long n = channel.write(allBuffers, 0, 2);
//应该返回7个字节
System.out.println("共写入多少字节:" + n);
accessFile.close();
channel.close();
}
public static void main1(String[] args) throws IOException {
final String fileName = "D:/test.log";
/**----------Gather------------*/
//FileChannel#write(java.nio.ByteBuffer[])
gather(fileName);
//FileChannel#write(java.nio.ByteBuffer[], int, int)
gather2(fileName);
}
}