Java NIO教程 Buffer
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存,这块内存中有很多可以存储byte(或int、char等)的小单元。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
为了理解Buffer的工作原理,需要熟悉它的三个属性:
- capacity
- position
- limit
简单的解释这三个属性的含义可以概括为:capacity代表这块Buffer的容量,position代表下一次读(或写)的位置,limit代表本次读(或写)的极限位置。这么简单说一下你当然是听不懂的啦(这样一下你就听懂了,岂不是显得我很没有存在感)所以下面开始详细的讲解。

capacity
作为一个内存块,Buffer有一个固定的大小值(这个大小是刚开始申请的),叫作“capacity”.你只能往里写capacity个byte、int,char等类型。
position
当你要写数据到Buffer中时,position表示当前可写的位置。初始的position值为0(也可以用过方法进行改变)。当一个byte、int等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
当读取数据时,也是从某个特定位置读。当从Buffer的position处读取数据完成时,position向前移动到下一个可读的位置。
limit
在写数据时,Buffer的limit表示你最多能往Buffer里写多少数据,position移动到limit写操作停止。初始limit的值等于Buffer的capacity。当读取数据时, limit表示你最多能读到多少数据,position移动到limit读操作停止。
无论在读数据时还是在写数据时,只要position超过了limit就会抛出异常。
控制position和limit的值
capacity的值是根据申请Buffer的大小和种类确定的,所以不能改变。而position和limit就可以根据我的需要而改变了,首先介绍一下如何查看这三个属性的值:buffer.limit()、buffer.position()、buffer.capacity()这三个方法直观、方便,我们就不再罗嗦。
接下来我们要着重看一下buffer.flip()这个方法一般用在写到读切换的时候。这个方法的能力就是将limit设为position的值,再是将position设为0。
这么做的用处是什么呢?你想想,在写数据的时候从Buffer的开始处—0位置到position位置之间已经写满了数据,如果这时候我们想要从头开始读数据的话,就要将position指向0,以便可以读取0位置的数据,然后逐个向下读取;但要读到什么位置为止呢?如果整个Buffer都读完的话,刚才所写的最后一个单元以后的单元,都是空,读取它们没有意义。所以读取到刚才所写的最后一个单元,是明智之举。而在将position置为0之前,position值就是刚才所写的最后一个单元的位置。所以在写到读切换的时候,将limit设为position的值,再是将position设为0。
这个明白了以后一切都顺了。buffer.clear()是清空Buffer的方法,但它没有真正的清除,只是将position置为0,将limit置为capacity;这样一来,你的写操作就可以将原来的数据覆盖了。就是这么简单。buffer.rewind()是将position置为0,这样一来就可以将buffer再重新读一遍,当然你还可通过它干很多事。
其实还有很多有用、有趣的方法,看看api文档吧。
基础实例 和 btye与其他类型的转换
说了这么多理论,再不上代码就有人得骂街了,来个最基础的申请buffer和基本的读写吧
ByteBuffer bb = ByteBuffer.allocate(48);
/*向ByteBuffer中put数据的时候,一下四种形式都可以
* put(byte b)
* put(byte[] src)
* put(byte[] src, int offset, int length)
* put(ByteBuffer src)
* 四种形式都会移动position指针
*/
bb.put(new byte[]{1,2,4,2,-13});
bb.flip();
//hasRemaining()的作用是看看position到没到limit位置
while(bb.hasRemaining()) {
System.out.println(bb.get());
}
还得来一段理论,再听我扯一会。Buffer共有类型有以下几种
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
- MappedByteBuffer(这哥们儿有点特殊,以后单独再讲)
Buffer在nio中的主要作用就是与channel交互。但这几种类型中能与channel交互的只有ByteBuffer(坑爹的吧!)所以在用其他类型Buffer的时候,一般都是先将ByteBuffer转化为想用的类型,用的是byteBuffer.asCharBuffer()、byteBuffer.asIntBuffer()等方法进行转换。这种方式用术语来讲,叫做“产生其他种类Buffer的视图”;意思就是底层是ByteBuffer,但看起来是其它种类的Buffer,可以用相应的方法,但是视图发生了读写,底层的ByteBuffer也会发生变化。
下面这段是将ByteBuffer转化为CharBuffer视图的例子
ByteBuffer bb = ByteBuffer.allocate(1024);
//将ByteBuffer转化为CharBuffer视图后,再调用put,ByteBuffer中的position指针不会移动
bb.asCharBuffer().put("Hello World");
//为了能正确的输出,这里改变了limit指针的位置,使之变到了字符数组的末尾
bb.limit("Hello World".length()*Character.BYTES);//字符数组长度*每个字符占的字节数
while(bb.hasRemaining()) {
System.out.print(bb.getChar());
}
/*也可用如下的方法输出
* while((c=bb.getChar())!=0) {
* System.out.print(c);
* }
*/
这段例子告诉我们,视图发生了读写,底层的ByteBuffer是有感知的,以及感知如何展现出来。但真正用的时候,没这么蛮烦。因为学了后面的channel,就知道了,channel直接就把整个ByteBuffer都拿走了,就不用这样一个个的输出了。而且一个个输出的话也可以直接利用视图层,向下看
ByteBuffer bb = ByteBuffer.allocate(1024);
IntBuffer ib = bb.asIntBuffer();
ib.put(new int[]{1,42,12,-12});
/*将ByteBuffer转化为IntBuffer视图后,再调用put,ByteBuffer中的position指针不会移动
* 但是所生成的IntBuffer中的position会按正常方式移动
* 而且整个IntBuffer的capacity会按照byte 和 int 之间的所占字节大小比例而改变*/
System.out.println("ByteBuffer.position = "+bb.position());
System.out.println("ByteBuffer.limit = "+bb.limit());
System.out.println("ByteBuffer.capacity = "+bb.capacity());
System.out.println("IntBuffer.position = "+ib.position());
System.out.println("IntBuffer.limit = "+ib.limit());
System.out.println("IntBuffer.capacity = "+ib.capacity());
ib.flip();
while(ib.hasRemaining()) {
System.out.println(ib.get());
}
会了这些Buffer的知识就差不多了,就到这里了。多打打例子代码、多体会体会,就可以洗洗睡了,拜拜
还是那句话,有问题及时告诉我
Java NIO教程 Buffer的更多相关文章
- Java NIO教程 目录
"Java NIO系列教程" 是笔者hans为NIO的初学者编写的一份入门教程,想仔细学习的同学可以按照顺序去阅读.由于我学的也不是特别的精,所以错误.疏漏在所难免,希望同学们指正 ...
- Java NIO 之 Buffer(缓冲区)
一 Buffer(缓冲区)介绍 Java NIO Buffers用于和NIO Channel交互. 我们从Channel中读取数据到buffers里,从Buffer把数据写入到Channels. Bu ...
- Java NIO 之 Buffer
Java NIO 之 Buffer Java NIO (Non Blocking IO 或者 New IO)是一种非阻塞IO的实现.NIO通过Channel.Buffer.Selector几个组件的协 ...
- Java NIO之Buffer(缓冲区)
Java NIO中的缓存区(Buffer)用于和通道(Channel)进行交互.数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这 ...
- 海纳百川而来的一篇相当全面的Java NIO教程
目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...
- Java NIO 教程
Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO. Java NIO提供了与 ...
- Java NIO之Buffer的使用
目录 Buffer简介 Buffer的核心属性 Buffer的创建与使用(ByteBuffer为例) 总结 参考资料 Buffer简介 缓冲区(Buffer):本质上是一个数组,用于临时保存.写入以及 ...
- JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁
IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. Java标准io回顾 在Java1.4之前的I/O系统中,提供 ...
- Java NIO教程 前言
阅读本文前,建议你先了解 旧I/O NIO 是 New I/O 的缩写,要了解它真正的内涵,需要掌握的知识还是比较多的.我努力在这几篇笔记里,勾勒出整个io的面貌.为大家的深入学习铺路. I/O简史 ...
随机推荐
- vb6获取字符串长度
用过VB5.0或者更早版本的读者应该知道VB有一个测试字符串长度的函数: Len.但当你升级到VB6时,会发现这里的Len并没有以前那么好用了——它变成了测试字符个数而不是字符串长度.就是说,当你用以 ...
- 如何修改SVN已提交项目的message log
直接在TortoiseSVN中修改过往日志,会提示: DAV request failed;it's possible that the repository's pre-revprop-change ...
- 【转】CSS z-index 属性的使用方法和层级树的概念
文章转自:CSS z-index 属性的使用方法和层级树的概念,另外加了一点自己的注释 CSS 中的 z-index 属性用于设置节点的堆叠顺序, 拥有更高堆叠顺序的节点将显示在堆叠顺序较低的节点前面 ...
- Hadoop SequenceFile数据结构介绍及读写
在一些应用中,我们需要一种特殊的数据结构来存储数据,并进行读取,这里就分析下为什么用SequenceFile格式文件. Hadoop SequenceFile Hadoop提供的SequenceFil ...
- OAF_文件系列4_实现OAF上传显示数据库动态图片Image(案例)
20150805 Created By BaoXinjian
- [MongoDB] 高可用架构方案
一.缘由: 众所周知,Mongodb是在高速发展期,一些特性架构难免会发生变化.这里就总结下,我目前所知道的Mongodb 的高可用架构都有哪些.目前Mongodb版本3.2. 二.结构介绍: 1.R ...
- Windows下查看进程及结束进程命令[转]
Windows下查看进程及结束进程命令 1)查看占用8080端口的进程号 >netstat –aon | findstr “8080” 结果:TCP 0.0.0.0:8080 ...
- mac与php环境
一.目录 apache目录:/etc/apache2/ mysql目录:/usr/local/mysql/ 站点目录:/Library/WebServer/Documents/ 二.mac系统给文件夹 ...
- Spring @Service生成bean名称的规则
今天碰到一个问题,写了一个@Service的bean,类名大致为:BKYInfoServcie.java dubbo export服务的配置: <dubbo:service interface= ...
- 谈谈Java利用原始HttpURLConnection发送POST数据
这篇文章主要给大家介绍java利用原始httpUrlConnection发送post数据,设计到httpUrlConnection类的相关知识,感兴趣的朋友跟着小编一起学习吧 URLConnectio ...