关于ByteBuffer的几个关键属性

byteBuffer几个方法含义:  

  •       capacity:缓冲区的容量;
  •   limit:缓冲区还有多少数据能够取出或者缓冲区还有多少容量用于存放数据;
  •   position:相当于一个游标(cursor),记录我们从哪里开始写数据,从哪里开始读数据。

三者关系:

  • capacity代表了Buffer的容量是不变的;
  • limit与position的差总是表示Buffer总可以读的数据,或者Buffer中可以写数据的容量。
  • position总是小于等于limit,limit总是小于等于capacity。
ByteBuffer主要标志位说明
标志位初始值说明
mark-1标记位
position0当前位置
limit指定的缓冲区容量已写入有效数据容量
capacity指定的缓冲区容量缓冲区容量

 

ByteBuffer的初始化

ByteBuffer提供两种不同的构造函数,其本质主要是构建的ByteBuffer类型不同,其中一种构造函数参照源代码:


  //第一种,分配的是DirectByteBuffer
  public static ByteBuffer allocateDirect(int capacity) {
        return new DirectByteBuffer(capacity);
  }
  //第二种,分配的是HeapByteBuffer
  public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapByteBuffer(capacity, capacity);
  }

详细两种不同类型的Buffer这里不展开讨论,但是大多数情况下,如果对性能没有太大要求的话,一般默认使用HeapByteBuffer。当我们执行初始化操作后: ByteBuffer.allocate(缓冲区大小);

其中初始化的值,分别为position=0,limit和capacity等于我们指定的缓冲区大小,mark默认为-1。网上有一些教程的图示默认显示了mark为起始点,其实是一种低级错误,让别人误以为mark就等于起始位置。

Put操作

顾名思义,put操作就是就是将数据放入缓冲区中,每一次put操作,都会position加上put进去的数据长度.position每加一,代表缓冲区内增加了一个字节的数据,具体put的操作原理如下: 

如果送入的数据大小大于缓冲区剩余容量,则会抛出异常:java.nio.BufferOverflowException,虽然可能有实际部分数据被写入缓冲区,但是flip之后,limit位置还是最后一次正确写入缓冲区的位置。

Flip操作

Flip,回针(请联想老式打字机),是让limit指向当前position的位置,position指向起始位置,此时position=0,进行这一部操作之后,就可以确定了当前缓冲区的有效数据。并且为数据读取做准备。

Get操作

Get操作,就是按照position当前位置,取出缓冲区的数据,每一次取操作之后,position都会get出的数据长度。同样,position每加一,代表从缓冲区内读取到了一个字节的数据,不过数据并不会被删除,只是单纯的读取操作。如果,get之后,position值大于limit值,则抛出异常:java.nio.BufferUnderflowException

Mark操作和Reset操作

mark,就是标记当前的位置,一旦后续进行reset操作之后,可以快速地定位到mark的位置。在某一些应用场合中,配合reset,这是一个非常方便的操作函数。

一旦进行过mark操作之后,后续读取操作中,如果再执行reset操作,就可以快速定位到标记位上:

 

Clear操作

Clear操作很简单,就是清空缓冲区的所有数据。因此,所有标志位都会被恢复成默认值,包括mark值,但是记住,不是数据,写入缓冲区的数据仍然保留,如果这时候执行get操作,仍然可以将数据获取出来。直观的话,可以直接看源代码:


    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

Slice操作

slice方法的作用,就是做数据分割,将当前的position到limit之间的数据分割出来,返回一个新的ByteBuffer,同时,mark标记重置为-1。不过这里注意,分割出来的数据的容量刚好就是数据长度,而不是被分割之前的长度。

快速清除已读取的数据

有时候,我们只是想要去掉前面一部分,而保留后面一部分数据,同时保持缓冲区的大小不变呢,这里提供一种思路,如下:



    public void clearPrePositionData(ByteBuffer byteBuffer) {
        ByteBuffer buffer2 = byteBuffer.slice();
        byteBuffer.clear();
        if (buffer2.capacity() > 0) {

            byteBuffer.put(buffer2);
        } else {
            byteBuffer.mark();
            byteBuffer.reset();
        }
        byteBuffer.flip();
    }

转载于:https://my.oschina.net/blacklands/blog/1186818

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值