6. 彤哥说netty系列之Java NIO核心组件之Buffer
——日拱一卒,不期而至!
你好,我是彤哥,本篇是netty系列的第六篇。
简介
上一章我们一起学习了Java NIO的核心组件Channel,它可以看作是实体与实体之间的连接,而且需要与Buffer交互,这一章我们就来学习一下Buffer的特性。
概念
Buffer用于与Channel交互时使用,通过上一章的学习我们知道,数据从Channel读取到Buffer,或者从Buffer写入Channel。
Buffer本质上是一个内存块,可以向里面写入数据,或者从里面读取数据,在Java中它被包装成了Buffer对象,并提供了一系列的方法用于操作这个内存块。
属性
为了更好地理解Buffer的数据结构,我们必须熟悉它的三个常用属性:
- capacity:容量
- position:当前位置
- limit:限制长度
在读模式和写模式下,position和limit的位置有所不同,见下图:
capacity
Buffer作为一个存储块,是有固定大小的,这个固定大小我们称作“容量”。
当Buffer写满之后,需要先清空或者读取数据,才能继续写入新的数据。
position
写模式下,position从0开始,每写入一个单位的数据,position前进一位,position最大可到达(capacity-1)的位置。
当Buffer从写模式切换为读模式时,position将重置为0。读取数据时,同样地,position每读取一个单位,前进一位,此时,position最大可到达limit的位置(实际最大可读取的位置是(limit-1))。
limit
写模式下,limit最大值等于capacity。
读模式下,limit最大值等于切换为读模式时position的值,本文来源工从号彤哥读源码。
这里可能有点绕,position类似于数组的下标,是从0开始的,limit表示最大可以读取或者写入的长度,capacity表示最大的容量,limit和capacity不是下标,类似于数组的长度,所以跟position比较需要-1。在写模式下,position指向的是下一个待写入的位置;在读模式下,position指向的是下一个待读取的位置。
类型
Java NIO自带的Buffer类型有:
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
与基本类型一样,每一种Buffer的基本单位长度不一样罢了。
其中,MappedByteBuffer是一种特殊的ByteBuffer,它使用内存映射的方式加载物理文件,并不会耗费同等大小的物理内存,是一种直接操作堆外内存的方式,读写性能比较高。
基本用法
上面我们学习了Buffer的数据结构以及常用的Buffer类型,它们怎么使用呢?常见的用法主要有四种:
- 将数据写入Buffer
- 切换为读模式flip()
- 从Buffer中读取数据
- 清空数据并切换为写模式clear()或者compact()
来个栗子
public class FileChannelTest {
public static void main(String[] args) throws IOException {
// 从文件获取一个FileChannel
FileChannel fileChannel = new RandomAccessFile("D:\\object.txt", "rw").getChannel();
// 分配一个Byte类型的Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 将FileChannel中的数据读出到buffer中,-1表示读取完毕
// buffer默认为写模式,本文来源工从号彤哥读源码
// read()方法是相对channel而言的,相对buffer就是写
while ((fileChannel.read(buffer)) != -1) {
// buffer切换为读模式
buffer.flip();
// buffer中是否有未读数据
while (buffer.hasRemaining()) {
// 读取数据
System.out.print((char)buffer.get());
}
// 清空buffer,为下一次写入数据做准备
// clear()会将buffer再次切换为写模式
buffer.clear();
}
}
}
allocate()
要获取一个Buffer对象,必须先分配它,每个Buffer类都有一个allocate()方法用于分配Buffer对象。
以下示例分配了一个容量为1024的ByteBuffer对象:
ByteBuffer buffer = ByteBuffer.allocate(1024);
下面是分配了一个容量为48的CharBuffer的对象:
CharBuffer buf = CharBuffer.allocate(48);
将数据写入Buffer
将数据写入Buffer有两种形式:
- 从Channel读出数据并写入Buffer,也叫从Channel读入Buffer
- 调用Buffer自己的put()方法写入数据
从Channel读入Buffer的示例如下:
int bytesRead = inChannel.read(buf); //读入Buffer
Buffer自己put()写入数据的示例如下:
buf.put(127);
当然,put()有很多不同的类型,比如在特定位置写入,写入不同类型的数据等等,可以在IDEA中按F12查看。
flip()
flip()方法用于将Buffer从写模式切换为读模式,position将切换到0位置,且limit将切换到刚才position的位置。
也就是说,position变成了可读数据的首位,limit表示可以读取的最大数据长度。
从Buffer中读取数据
从Buffer中读取数据也有两种形式:
- 从Buffer读取数据,并写入Channel,也叫作从Buffer写入Channel
- 调用Buffer自己的get()方法读取数据
从Buffer写入Channel的示例如下:
// 本文来源工从号彤哥读源码
int bytesWritten = inChannel.write(buf);
调用Buffer自己的get()方法读取数据的示例如下:
byte aByte = buf.get();
当然,get()有很多不同的类型,比如从特定的位置读取,读取不同类型的数据等等,可以在IDEA中按F12查看。
rewind()
rewind()方法会重置position为0,但limit保持不变,因此可以用来重新读取数据。通常是在重新读取数据之前调用。
clear()
clear()方法用于清空整个Buffer,并将Buffer从读模式切换回写模式,且position归位到0位置。
compact()
compact()方法用于清空已读取的数据,并将未读取的数据移至Buffer的头部,position的位置移动到从头开始计算的未读取的数据的下一个位置,它也会将Buffer从读模式切换回写模式。
mark() 和 reset()
mark()方法用于标记给定位置,然后可以在之后通过reset()方法重新回到mark的位置,示例如下:
buffer.mark();
//多次调用buffer.get(),例如在解析过程中。
buffer.reset(); //将位置重新设置为标记。
总结
今天我们学习了Java NIO核心组件Buffer,它经常跟Channel联合起来使用。讲到这里我们一直在使用FileChannel在举例,那么它们到底跟网络编程有什么关系呢?请听下回分解。
参考
http://tutorials.jenkov.com/java-nio/channels.html
最后,也欢迎来我的工从号彤哥读源码系统地学习源码&架构的知识。
6. 彤哥说netty系列之Java NIO核心组件之Buffer的更多相关文章
- 5. 彤哥说netty系列之Java NIO核心组件之Channel
你好,我是彤哥,本篇是netty系列的第五篇. 简介 上一章我们一起学习了如何使用Java原生NIO实现群聊系统,这章我们一起来看看Java NIO的核心组件之一--Channel. 思维转变 首先, ...
- 7. 彤哥说netty系列之Java NIO核心组件之Selector
--日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第七篇. 简介 上一章我们一起学习了Java NIO的核心组件Buffer,它通常跟Channel一起使用,但是它们在网络IO中又该如何 ...
- 4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了)
你好,我是彤哥,本篇是netty系列的第四篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们一起学习了Java中的BIO/NIO/AIO的故事,本章将带着大家一起使 ...
- 3. 彤哥说netty系列之Java BIO NIO AIO进化史
你好,我是彤哥,本篇是netty系列的第三篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们介绍了IO的五种模型,实际上Java只支持其中的三种,即BIO/NIO/ ...
- 1. 彤哥说netty系列之开篇(有个问卷调查)
你好,我是彤哥,本篇是netty系列的第一篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 本文主要讲述netty系列的整体规划,并调查一下大家喜欢的学习方式. 知识点 ne ...
- 2. 彤哥说netty系列之IO的五种模型
你好,我是彤哥,本篇是netty系列的第二篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 本文将介绍linux中的五种IO模型,同时也会介绍阻塞/非阻塞与同步/异步的区别. ...
- Netty精粹之JAVA NIO开发需要知道的
学习Netty框架以及相关源码也有一小段时间了,恰逢今天除夕,写篇文章总结一下.Netty是个高效的JAVA NIO框架,总体框架基于异步非阻塞的设计,基于网络IO事件驱动,主要贡献在于可以让用户基于 ...
- Java NIO 核心组件学习笔记
背景知识 同步.异步.阻塞.非阻塞 首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下[1]. 同步:API调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节). 异步:相 ...
- 一文让你彻底理解 Java NIO 核心组件
背景知识 同步.异步.阻塞.非阻塞 首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下. 同步:API调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节). 异步:相对于同 ...
随机推荐
- Docker 实战—使用 Dockerfile 构建镜像
Dockerfile 指令详解请访问:https://www.cnblogs.com/cloudfloating/p/11737447.html 使用 Alpine Linux 作为基础镜像 Alpi ...
- Python中Linux开发的技巧
Python的Linux基础目录 操作系统 Windows和Linux的区别 常用基本命令1.操作系统 1 操作系统的作用:向上支持应用软件的运行,向下控制硬件,软件和硬件的过渡层Linux的版本 ...
- Java后端开发工作 - 写接口
我在公司的工作内容是,对于一个BS应用,负责服务器端开发工作,Java语言.与前端开发人员合作,最终提供给前端RESTFUL接口,保证页面正常响应. 经验之谈 一个接口可以理解为一个业务逻辑,一个业务 ...
- Spring Boot实战之定制type Formatters
本文首发于个人网站:Spring Boot实战之定制type Formatters 前面我们有篇文章介绍了PropertyEditors,是用来将文本类型转换成指定的Java类型,不过,考虑到Prop ...
- [Flink]Flink1.6三种运行模式安装部署以及实现WordCount
前言 Flink三种运行方式:Local.Standalone.On Yarn.成功部署后分别用Scala和Java实现wordcount 环境 版本:Flink 1.6.2 集群环境:Hadoop2 ...
- 相关推导式-Python
列表.’字典等推导式 #利用zip()函数同时给多个变量赋值 a = [1,2,3,4,5] b = [4,5,6,7,8] c = [9,2,3,4,0] l = [[1,2],[3,4]] for ...
- B2B市场新的营销思路
随着互联网+时代的到来,企业与企业之间的联系已经慢慢从传统的服务模式转变为网上服务,企业与企业之间通过网络,进行数据信息的交换.传递,开展交易活动的商业模式我们称之为B2B B2B使企业大大节约了企业 ...
- 队列+BFS (附vector初试)
优先队列的使用: include<queue>//关联头文件 struct node{ int x,y; friend bool operator < (node d1,node d ...
- ArcGIS API For Javascript :如何制作地图切换器
大部分情况下我们开发会使用原生的地图切换器,由于每个项目的页面风格不同,业务场景不同,因此需要做一些样式不同的地图切换器. 首先可以照猫画虎,自己照着地图切换器的样式抄一个,或者看看主流的地图切换器都 ...
- 用例图浅谈以及OOA再到情景分析的面向对象电梯的设计(慕课东北大学)面向对象设计思维模式
上班初期还不太适应,平时学习进度也跟不上,节奏慢下来会有时间更新的了. Diagram 这边以学生课程报名系统为例 这就是一种简单的用例图 用例图可以给读者提供的信息非常丰富,但是缺点是都是概 ...