上一篇知道了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操作,以及对网上那个例子,进行了更详细一点的说明。

Java NIO学习与记录(三): Scatter&Gather介绍及使用的更多相关文章

  1. Java NIO学习与记录(八): Reactor两种多线程模型的实现

    Reactor两种多线程模型的实现 注:本篇文章例子基于上一篇进行:Java NIO学习与记录(七): Reactor单线程模型的实现 紧接着上篇Reactor单线程模型的例子来,假设Handler的 ...

  2. Java NIO 学习笔记(三)----Selector

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  3. Java NIO学习与记录(五): 操作系统的I/O模型

    操作系统的I/O模型 在开始介绍NIO Reactor模式之前,先来介绍下操作系统的五种I/O模型,了解了这些模型,对理解java nio会有不小的帮助. 先来看下一个服务端处理一次网络请求的流程图: ...

  4. Java NIO学习与记录(二):FileChannel与Buffer用法与说明

    FileChannel与Buffer用法与说明 上一篇简单介绍了NIO,这一篇将介绍FileChannel结合Buffer的用法,主要介绍Buffer FileChannel的简单使用&Buf ...

  5. Java NIO学习与记录(七): Reactor单线程模型的实现

    Reactor单线程模型的实现 一.Selector&Channel 写这个模型需要提前了解Selector以及Channel,之前记录过FileChannel,除此之外还有以下几种Chann ...

  6. Java NIO学习与记录(六): NIO线程模型

    NIO线程模型 上一篇说的是基于操作系统的IO处理模型,那么这一篇来介绍下服务器端基于IO模型和自身线程的处理方式. 一.传统阻塞IO模型下的线程处理模式 这种处理模型是基于阻塞IO进行的,上一篇讲过 ...

  7. Java NIO学习与记录(一):初识NIO

    初识 工作中有些地方用到了netty,netty是一个NIO框架,对于NIO却不是那么熟悉,这个系列的文章是我在学习NIO时的一个记录,也期待自己可以更好的掌握NIO. 一.NIO是什么? 非阻塞式I ...

  8. Java NIO学习与记录(四): SocketChannel与BIO服务器

    SocketChannel与BIO服务器 SocketChannel可以创建连接TCP服务的客户端,用于为服务发送数据,SocketChannel的写操作和连接操作在非阻塞模式下不会发生阻塞,这篇文章 ...

  9. Java NIO 学习笔记(二)----聚集和分散,通道到通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

随机推荐

  1. 利率计算--web版--软件工程

    1.客户说:帮我开发一个复利计算软件. 完成复利公式计算程序,并成功PUSH到github上. 截止时间:3.10晚12点之前. 按照这个要求完成了. 演示. 计算:本金为100万,利率或者投资回报率 ...

  2. [mongoDB] mongoDb

    mongodb memcached redis        kv数据库(key/value) mongodb 文档数据库,存储的是文档(Bson->json的二进制化). 特点:内部执行引擎为 ...

  3. Spring源码解析 - BeanFactory

    BeanFactory是Spring实现依赖注入的核心接口.提供应用的统一配置注册功能,实现业务开发解偶.使用getBean可以代替单例,原型设计模式. 顶重要的BeanFactory里注释写得太好了 ...

  4. C# WebApi 过滤器的使用开发接口必备利器

    在WEB Api中,引入了面向切面编程(AOP)的思想,在某些特定的位置可以插入特定的Filter进行过程拦截处理.引入了这一机制可以更好地践行DRY(Don’t Repeat Yourself)思想 ...

  5. mysql - json串新增字段

    1.建表 -- 建表 drop table if exists ta_product2; CREATE TABLE ta_product2( id int primary key auto_incre ...

  6. 企业搜索引擎开发之连接器connector(十八)

    创建并启动连接器实例之后,连接器就会基于Http协议向指定的数据接收服务器发送xmlfeed格式数据,我们可以通过配置http代理服务器抓取当前基于http协议格式的数据(或者也可以通过其他网络抓包工 ...

  7. prog1,2,3

    1.第一版本程序Prog1:+ 给定一个数组,实现数组元素求和:具体要求:实现对一维数组(a[100])的所有元素相加运算.+ 数据准备:a)数组长度:100:b)数组数据来源:实验数据A列:1~10 ...

  8. C#学习(1):类型约束

    where T : class泛型类型约束 类型参数约束,.NET支持的类型参数约束有以下五种: where T : struct | T必须是一个结构类型 where T : class T必须是一 ...

  9. [Oracle]Oracle数据库CPU利用率很高解决方案

    Oracle数据库经常会遇到CPU利用率很高的情况,这种时候大都是数据库中存在着严重性能低下的SQL语句,这种SQL语句大大的消耗了CPU资源,导致整个系统性能低下.当然,引起严重性能低下的SQL语句 ...

  10. 开源日志收集Exceptionless简单使用

    这两天在研究一个开源的日志收集工具Exceptionless 官网地址:https://exceptionless.com/GitHub地址:https://github.com/exceptionl ...