NIO:关于ByteBuffer的几个关键属性

byteBuffer几个方法含义:  java

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

三者关系:函数

  • capacity表明了Buffer的容量是不变的;
  • limit与position的差老是表示Buffer总能够读的数据,或者Buffer中能够写数据的容量。
  • position老是小于等于limit,limit老是小于等于capacity。

ByteBuffer主要标志位说明

标志位 初始值 说明
mark -1 标记位
position 0 当前位置
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(缓冲区大小);this

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

Put操做

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

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

Flip操做

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

Get操做

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

Mark操做和Reset操做

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

一旦进行过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();
    }
相关文章
相关标签/搜索