• Java NIO学习与记录(三): Scatter&Gather介绍及使用


    上一篇知道了Buffer的工作机制,以及FileChannel的简单用法,这一篇介绍下 Scatter&Gather

    1.Scatter(分散)

    用于描述在Channel中读取的数据分散在不同的Buffer里。

    接着上一篇的例子(rua文件内容为123456789),改造下代码:

    
    readFile = new RandomAccessFile("D:\\rua.txt", "r");
    FileChannel readChannel = readFile.getChannel();
    ByteBuffer first = ByteBuffer.allocate(2); //第一块buffer
    ByteBuffer second = ByteBuffer.allocate(2); //第二块buffer
    ByteBuffer[] byteBuffers = {first, second};
    long bytesRead = readChannel.read(byteBuffers); //从通道里读取数据到Buffer内(最大不超过Buffer容积)
    while (bytesRead != -1) { //当读不到任何东西时返回-1
        System.out.println("\nheader里的数据------此时byteRead=" + bytesRead);
        first.flip(); //切换到Buffer读模式,读模式下可以读取到之前写入Buffer的数据
        while (first.hasRemaining()) {
           System.out.print("-" + (char) first.get()); //第一块Buffer读出的数据用减号分割,用于跟第二块区分
        }
        first.clear();
        System.out.println("\nbody里的数据------此时byteRead=" + bytesRead);
        second.flip();
        while (second.hasRemaining()) {
          System.out.print("+" + (char) second.get()); //第二块Buffer读出的数据用加号分割,用于跟第一块区分
        }
        second.clear(); // 切换回Buffer的写模式
        System.out.println("\n----------------------------------------------");
        bytesRead = readChannel.read(byteBuffers); //跟上面一样,再次从通道读取数据到Buffer中
    }
    System.out.print("\n-----------程序结束");
    

    上面的代码开了两个Buffer,然后传给了Channel.read一个Buffer数组,运行结果如下:

    
    header里的数据------此时byteRead=4
    -1-2
    body里的数据------此时byteRead=4
    +3+4
    ----------------------------------------------
    
    header里的数据------此时byteRead=4
    -5-6
    body里的数据------此时byteRead=4
    +7+8
    ----------------------------------------------
    
    header里的数据------此时byteRead=1
    -9
    body里的数据------此时byteRead=1
    
    ----------------------------------------------
    
    -----------程序结束
    

    可以看到,文件里的内容被分段加载出来了,first buffer里首选读取一段,然后接着second buffer再接着读取接下来的一段。上面例子符合Scatter的描述。

    看过网上一些文章,说的最多的例子就是协议头数据体分开处理的例子:

    假设通过Channel获取到的数据存在固定长度的协议头,以及已知最大长度限制的数据体,就可以通过两个Buffer来接收,一个是header buffer,一个是body buffer,

    但这个对数据要求很严苛,结合上面的例子,不难发现,想要做到准确无误的处理这个例子,就得要求事先必须知道header的长度,以及数据体的最大长度上限,为什么要这样呢?因为如果不知道header的长度,那么header buffer就可能会读到body buffer里的东西或者body buffer里读到header buffer里的东西,如果不知道body的上限长度,那么如果body数据长度超过了body buffer的长度,body里的数据就会再次读到header buffer中去(这个可以结合上面的例子理解)。

    2.Gather(聚集)

    用于描述在将不同Buffer里的数据写到同一个Channel中去。

    来看个例子:

    
    readFile = new RandomAccessFile("D:\\haha.txt", "rw");
    FileChannel channel = readFile.getChannel();
    ByteBuffer first = ByteBuffer.allocate(5); //第一块buffer
    ByteBuffer second = ByteBuffer.allocate(5); //第二块buffer
    first.put("aa".getBytes());
    second.put("bb".getBytes());
    first.flip();
    second.flip();
    ByteBuffer[] byteBuffers = {first, second};
    channel.write(byteBuffers);
    System.out.print("\n-----------程序结束");
    

    运行结束后,haha.txt里的内容为:

    
    aabb
    

    可以看到,最终写入的数据就是按照顺序把两个buffer里的内容传输进去了。

    同样的,还是以网上的协议头数据体的例子说事儿,这个跟Scatter下的传输方式比较起来就不会那么严格了,看到上面,初始容积为5个字节,但实际写到文件里的每个buffer仍然是两个字节,因为Gather模式下,Channel读取Buffer数据的时候,只会读取position到limit间的数据(可读区域),因此这里不用像多Buffer读一样要求那么严格,我们可以随意定义header buffer的长度,只要大于协议头本身长度即可,body buffer的要求其实是同上,也是大于数据体的长度上限即可。

    这就是Scatter和Gather的全部内容了~其实简单理解,就是多Buffer操作,以及对网上那个例子,进行了更详细一点的说明。

  • 相关阅读:
    Navicat 15 最新破解版下载_永久激活注册码(附图文安装教程) Java大师
    idea30天免费试用,看看到底好不好用 Java大师
    TypeScript学习001
    [PE 741] Binary grid colouring
    ORACLE 查看被锁的表、导致锁表的目标机器、及对应锁表语句
    Hook Formulae and Schubert Calculus
    7个葫芦娃的养鸡日记系列1
    protobuf 'NoneType' object has no attribute 'message_types_by_name'
    windows bat 跳转到当前目录执行命令
    Android64位库编译遇到的问题和处理方法
  • 原文地址:https://www.cnblogs.com/hama1993/p/10487480.html
Copyright © 2020-2023  润新知