1. MappedByteBuffer的使用
介绍
- 使用MappedByteBuffer可以不在内存中将文件修改,使用堆外内存,不需要将文件进行而外的拷贝。
- 是一个操作系统级别的文件修改
案例
直接读取文件并修改,不进行拷贝
对1.txt文件进行读取,并直接修改其中的值。
public static void main(String[] args) throws Exception {
RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt","rw");
// 获取对应通道
FileChannel channel = randomAccessFile.getChannel();
/**
* 参数:
* 1. 模式:表示使用的读写模式
* 2. 表示可以直接修改的开始位置
* 3. 表示映射到内存的大小,即将文件的多少个字节映射到内存
* 可以修改的范围为 [0,5)
*/
MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
mappedByteBuffer.put(0, (byte) 'H');
mappedByteBuffer.put(3, (byte) '8');
randomAccessFile.close();
}
效果
源文件
修改后文件
2. 分散和聚集
介绍
- Scattering将数据写入到buffer时,可以采用buffer数组,依次写入(一个buffer满了就写入第二个数组)被叫做分散
- Gattering从buffer读取数据的时候,可以采用buffer数组,依次读入 被叫做聚集
案例
使用Socket编程,模拟网络通信中的收发操作。
使用数组完成对于数据的存放和发送。
接受时,将返回结果依次放入第0个和第1个buffer中,发送时,依次从第0个和第1个数组中取出元素。
public class ScatteringAndGatheringTest {
public static void main(String[] args) throws IOException {
// 使用 ServerSocketChannel 和 SocketChannel 网络
// 打开通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 定义通道未7000端口
InetSocketAddress inetSocketAddress = new InetSocketAddress(7000);
// 绑定通道和端口到socket
serverSocketChannel.socket().bind(inetSocketAddress);
// 创建buffer数组
ByteBuffer[] byteBuffers = new ByteBuffer[2];
byteBuffers[0] = ByteBuffer.allocate(5);
byteBuffers[1] = ByteBuffer.allocate(3);
// 等待客户端链接
SocketChannel socketChannel = serverSocketChannel.accept();
// 从客户端接受
int messageLength = 8;
//循环读取
while (true) {
int byteRead = 0;
while (byteRead < messageLength) {
long read = socketChannel.read(byteBuffers);
byteRead += read;
System.out.println("读取了" + byteRead);
// 查看buffer的position和limit
Arrays.asList(byteBuffers).stream().map(buffer -> "position=" + buffer.position() +
",limit" + buffer.limit()).forEach(System.out::println);
}
// 将所有的buffer反转
Arrays.asList(byteBuffers).stream().forEach(Buffer::flip);
// 将数据返回给客户端
long byteWrite = 0L;
while (byteWrite < messageLength) {
long write = socketChannel.write(byteBuffers);
byteWrite += write;
}
// 将所有的buffer进行clear操作
Arrays.asList(byteBuffers).forEach(Buffer::clear);
System.out.println("byteRead:=" + byteRead + ",byteWrite=" + byteWrite + ",messageLength" + messageLength);
}
}
}
结果
使用Scoket调制助手,与程序程序中的7000端口建立连接。
发送11111字节的数据
看到结果如下。
继续发送三个1,buffer数组被填满。将数据写入buffer
最终结果如下