【NIO】scatter/gather 绝地灬酷狼 2022-05-30 02:19 145阅读 0赞 # 前言 # Github:[https://github.com/yihonglei/jdk-source-code-reading][https_github.com_yihonglei_jdk-source-code-reading](java-nio) # 一 scatter/gather概述 # Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel中读取或者写入到Channel的操作。 **分散(scatter):** 从Channel中读取数据,"分散"的写入到多个Buffer中。 **聚集(gather):** 从多个Buffer中读取数据"聚集"在一起,写入到一个Channel中。 scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息, 你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。 # 二 Scattering Reads # Scattering Reads是指数据从一个channel读取到多个buffer中。如下图描述: ![Center][] **代码示例如下:** package com.jpeony.nio.scattergather; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * 通道中的数据分散写入到多个缓冲区 * * @author yihonglei */ public class ScatterTest { public static void main(String[] args) { // 指定构建文件 File file = new File("C:\\mycode\\hello.txt"); try (RandomAccessFile raf = new RandomAccessFile(file, "rw"); FileChannel channel = raf.getChannel()) { // 分配缓冲区大小 ByteBuffer header = ByteBuffer.allocate(48); ByteBuffer body = ByteBuffer.allocate(1024); // 缓冲区加入数组 ByteBuffer[] bufferArray = {header, body}; /** * buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。 * read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer, * 当一个buffer被写满后,channel紧接着向另一个buffer中写。 */ channel.read(bufferArray); // Buffer切换模式之前,即处于写模式下,打印Buffer,查看position, limit, capacity属性 System.out.println(header.toString()); System.out.println(body.toString()); // Buffer切换为读模式 header.flip(); body.flip(); // 分割线 System.out.println("==============切换模式前后Buffer中position, limit ,capacity属性================="); // 切换模式之后,打印Buffer,查看position, limit, capacity属性 System.out.println(header.toString()); System.out.println(body.toString()); // 打印缓冲区数据 while (header.hasRemaining()) { System.out.print((char) header.get()); } System.out.println("\n============================="); while (body.hasRemaining()) { System.out.print((char) body.get()); } } catch (Exception e) { e.printStackTrace(); } } } 注意buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。 read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer, 当一个buffer被写满后,channel紧接着向另一个buffer中写。 Scattering Reads在移动下一个buffer前,必须填满当前的buffer,这也意味着它不适用于动态消息。 换句话说,如果存在消息头和消息体,消息头必须完成填充(例如 128byte),Scattering Reads才能正常工作。 # 三 Gathering Writes # Gathering Writes是指数据从多个buffer写入到同一个channel。如下图描述: ![Center 1][] **代码示例如下:** package com.jpeony.nio.scattergather; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * 多个缓冲区中的数据聚合写入到通道 * * @author yihonglei */ public class GatherTest { public static void main(String[] args) { // 指定构建文件 File file = new File("C:\\mycode\\hello.txt"); try (RandomAccessFile raf = new RandomAccessFile(file, "rw"); FileChannel channel = raf.getChannel()) { // 分配缓冲区大小 ByteBuffer header = ByteBuffer.allocate(8); ByteBuffer body = ByteBuffer.allocate(8); // 写入数据到Buffer header.put(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}); body.put(new byte[]{9, 10, 11, 12, 13, 14, 15, 16}); // Buffer放入数组 ByteBuffer[] bufferArray = {header, body}; // 切换模式之前,即处于写模式下,打印Buffer,查看position, limit, capacity属性 System.out.println(header.toString()); System.out.println(body.toString()); // 分割线 System.out.println("==============切换模式前后Buffer中position, limit ,capacity属性================="); // 切换为读模式 header.flip(); body.flip(); // 切换模式之后打印Buffer,查看position, limit, capacity属性 System.out.println(header.toString()); System.out.println(body.toString()); /** * 写入数据到Channel: * buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel, * 注意只有position和limit之间的数据才会被写入。 */ long bytes = channel.write(bufferArray); System.out.println("从Buffer读取写入到Channel的字节数:" + bytes); } catch (Exception e) { e.printStackTrace(); } } } buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel, 注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量为128byte, 但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。 因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息。 [https_github.com_yihonglei_jdk-source-code-reading]: https://github.com/yihonglei/jdk-source-code-reading [Center]: /images/20220530/59c854f8e53c43a7bf7d1647de6368da.png [Center 1]: /images/20220530/95d3c51e630b4ac991eff72bd2255354.png
还没有评论,来说两句吧...