博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NIO-ByteBuffer
阅读量:6201 次
发布时间:2019-06-21

本文共 4138 字,大约阅读时间需要 13 分钟。

hot3.png

ByteBuffer 是jdk内部提供的字节缓冲区,内存分配主要分为堆内存和直接内存(堆外内存)。

7ca5316594ffc50ffb0cef3d309c9bab4cf.jpg

1、堆内存分配

//分配一个容量为32的堆缓冲区ByteBuffer buffer = ByteBuffer.allocate(32);

2、直接内存

ByteBuffer buffer = ByteBuffer.allocateDirect(32);

 

字节数据操作

ByteBuffer 有4个属性 capacity、limit、position、mark

capacity:容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变。

limit:表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作。可以通过下面的方法修改

public final Buffer limit(int newLimit)

position: 位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变改值,为下次读写作准备。可以通过下面的方法修改

public final Buffer position(int newPosition)

mark标记: 调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置

示例代码:

@Test    public void test(){        //分配一个容量为32的堆缓冲区        ByteBuffer buffer = ByteBuffer.allocate(32);        //初始状态        System.out.println(String.format("初始状态 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));        //添加字节        buffer.put("hello".getBytes());        //输出        System.out.println(String.format("添加字节后 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));        //读取的内容是position到limit之间数据 调用该方法设置 limit = position;position = 0;mark = -1;        buffer.flip();        //输出        System.out.println(String.format("flip后--》 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));        //读取数据        byte[] newArray = new byte[buffer.remaining()] ;        buffer.get(newArray);        String value = new String(newArray);        System.out.println("读取到的数据:"+value);        System.out.println(String.format("读取后--》 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));        //调用mark标记当前position的值        buffer.mark();        //设置limit的值 position到limit的长度为可写的长度 所有设置为buffer.position()+新字节的长度        buffer.limit(buffer.position()+"abcdef".getBytes().length);        buffer.put("abcdef".getBytes());        //写入后position会向后移动 position=limit        System.out.println(String.format("再次写入后--》 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));        //读取新写入的内容,需要将position设置为mark的位置        buffer.reset();        System.out.println(String.format("再次读取reset后--》 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));        //读取数据        byte[] newArray2 = new byte[buffer.remaining()] ;        buffer.get(newArray2);        String value2 = new String(newArray2);        System.out.println("读取到的数据:"+value2);        System.out.println(String.format("读取后--》 limit:%d,capacity:%d,position:%d",buffer.limit(),buffer.capacity(),buffer.position()));    }

运行结果:

558ea54052761f5fe03eaaf42a72ace2053.jpg

 

分析:

1、向一个容量为32的字节缓冲区中写入hello字符后,position=5

fe8d92314d44948913087dc4c27bcd9325a.jpg

2、读取写入的字节必须调用flip,调用后limit = position=5;position = 0;mark = -1; 

ec786b3f11664447a621d0b03bc7983be55.jpg

然后调用下面的方法去读取缓冲区的数据。buffer.remaining()=limit - position,读取的内容是从position到limit之间的内容。

byte[] newArray = new byte[buffer.remaining()] ;buffer.get(newArray);

9c7d24b44e8e8a0af4d196925ab2c5731d1.jpg

 

3、读取后,position指针会向后移动,position=limit

daff3291a4a3b4c9fe1abb9d221be954402.jpg

4、再次写入字节abcdef,需要调用mark方法,记录一下当前position的值

b3b039754c873bb8812e8a7a7118361b975.jpg

设置limit的值为(position+abcdef的长度),然后调用put方法写入字节。

cc61d8255eb5aa366033e1711ecf84ea51f.jpg

调用buffer.reset(); 将position设置为mark的值(5)

b68f16539b6dcffcb944505bf24d016dd29.jpg

cacb1dc8c59e0400f66e5ace4c76d245a2f.jpg

最后读取position与limit之间的字节数据就是abcdef。

 

 Buffer方法汇总: 

reset():    把position设置成mark的值,相当于之前做过一个标记,现在要退回到之前标记的地方

clear():    position = 0;limit = capacity;mark = -1;  有点初始化的味道,但是并不影响底层byte数组的内容
flip():    limit = position;position = 0;mark = -1;  翻转,也就是让flip之后的position到limit这块区域变成之前的0到position这块,翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态
rewind():    把position设为0,mark设为-1,不改变limit的值
remaining():    return limit - position;返回limit和position之间相对位置差
hasRemaining():    return position < limit返回是否还有未读内容
compact():    把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。如果先将positon设置到limit,再compact,那么相当于clear()
get():    相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
get(int index):    绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position
get(byte[] dst, int offset, int length):    从position位置开始相对读,读length个byte,并写入dst下标从offset到offset+length的区域
put(byte b):    相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备
put(int index, byte b):    绝对写,向byteBuffer底层的bytes中下标为index的位置插入byte b,不改变position
put(ByteBuffer src):    用相对写,把src中可读的部分(也就是position到limit)写入此byteBuffer
put(byte[] src, int offset, int length):    从src数组中的offset到offset+length区域读取数据并使用相对写写入此byteBuffer

 

转载于:https://my.oschina.net/suzheworld/blog/3007051

你可能感兴趣的文章
HDU 4135 Co-prime(容斥+数论)
查看>>
The Little Prince-11/29
查看>>
【Moqui业务逻辑翻译系列】--UBPL Introduction同意的商业处理文库介绍
查看>>
Eclipse控制台输出信息的控制(引用其他人的博客)
查看>>
poj 1088 滑雪
查看>>
bzoj3891[Usaco2014 Dec]Piggy Back*
查看>>
分解质因数的技巧
查看>>
Linux安装JDK步骤
查看>>
C#统计英文文本中的单词数并排序
查看>>
10 个免费的 C/C++ 集成开发环境
查看>>
Django 中 发送邮件
查看>>
USACO 2.3 ;零的数列
查看>>
八、桥接模式--结构模式(Structural Pattern)
查看>>
iOS 在制作framework时候对aggregate的配置
查看>>
Absolute Horizontal And Vertical Centering In CSS
查看>>
store the XML schema with the data
查看>>
访问某类型的元数据的方式-TypeDescriptor 类
查看>>
Oracle 18c 数据库中scott用户不存在的解决方法
查看>>
TensorFlow安装 通过Anaconda Win10 64位 cpu and gpu
查看>>
【leetcode】Max Area of Island
查看>>