Nio Buffer

作者: 这是一个随便起的昵称 | 来源:发表于2018-07-07 18:51 被阅读16次

Buffer

Buffer 是一种特殊元数据类型的容器,是线性有序的序列。Buffer 是一个抽象类,它定义一系列的通用方法。其子类有
ByteBuffer、CharBuffer、IntBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer

Buffer 中重要的几个属性是

  1. capacity
    Buffer 中 backing array 的 length ,即Buffer 的容量。
  2. limit
    Buffer 中 的可读取数据的范围,limit 到 capacity 之间的数据不可读
  3. position
    Buffer 中可操作数据的位置。
  4. mark
    Buffer 中的标记位,通常与 reset() 方法一起使用。

0<=mark<=position<=limit<=capacity

重要的方法

  1. clear()
    为存放新数据做好准备,position = 0,limit = capacity
  2. flip()
    为获取数据做好准备,limit = position, position = 0
  3. rewind()
    为重新读取数据做好准备,poition = 0。通常的操作如下
buffer.mark();
buffer.rewind();
...
获取需要的数据
...
buffer.reset();//恢复原本状态

All Method

Modifier And Type Method Description
abstract Object array() get backing array
abstract int arrayOffset() get backing arrayOffset
int capacity() 容量
Buffer clear() position = 0,limit = capacity,mark = -1
Buffer flip() limit = position,position = 0,mark = -1
abstract boolean hasArray() 是否有 backing array
boolean hasRemaining 是否剩余未读取数据
abstract boolean isDirect()
abstract boolean isReadOnly()
int limit()
Buffer limit(int newLimit)
Buffer mark() mark = position
int position() 当前可操作位置
Buffer position(int newPosition)
int remaining() limit - position
Buffer reset() position = mark
Buffer rewind() position = 0,mark = -1

Buffer 的所有子类中我认为 ByteBuffer 最有代表性,所以我将会仔细学习 ByteBuffer 中的 Api

ByteBuffer

  1. 实例化方法
  • ByteBuffer.allocate(int capacity)
  • ByteBuffer.allocateDirect(int capacity)
  • ByteBuffer.wrap(byte[] array)
  • ByteBuffer.wrap(byte[] array, int offset, int length)
  1. byte[] array()
    返回容器内部用于存储“数据的字节数组”,注意这里是返回的引用!修改数组中的值将会影响缓冲区。调用此方法之前需要调用 hasArray() 来检测 array()是否被支持
ByteBuffer byteBuffer = ByteBuffer.allocate(30);
byte[] bytes = byteBuffer.array();
print(Arrays.toString(bytes));
bytes[0] = 12 & 0xFF;
print(Arrays.toString(byteBuffer.array()));

output

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  1. int arrayOffset()
    获取缓冲区中第一个元素,在backing array 中的偏移量。
    这个方法我没查到怎么用,绝大数情况下返回值返回为0。
    查看源码也是一直被赋值为 0
    HeapByteBuffer(int cap, int lim) {            // package-private

        super(-1, 0, lim, cap, new byte[cap], 0);
        /*
        hb = new byte[cap];
        offset = 0;
        */
    }

补充:在查看源码的时候,发现了这个方法不为零的时候。调用 byteBuffer.slice() 方法的时候,返回的 arrayOffset() 为byteBuffer.position()

public ByteBuffer slice() {
    return new HeapByteBuffer(hb,
                                    -1,
                                    0,
                                    this.remaining(),
                                    this.remaining(),
                                    this.position() + offset);
}
  1. abstract IntBuffer asIntBuffer()
    转化为 IntBuffer,需要注意的是 这里转化后 array() 不可用,会抛出异常。原因是转化生成的 IntBuffer 实际上只是一个装饰器,在IntBuffer 上的一系列操作只是调用,ByteBuffer 的一系列方法。有点绕,还是看一下源码
//HeapByteBuffer
 public IntBuffer asIntBuffer() {
        int size = this.remaining() >> 2;
        int off = offset + position();
        return (bigEndian
                ? (IntBuffer)(new ByteBufferAsIntBufferB(this,
                                                             -1,
                                                             0,
                                                             size,
                                                             size,
                                                             off))
                : (IntBuffer)(new ByteBufferAsIntBufferL(this,
                                                             -1,
                                                             0,
                                                             size,
                                                             size,
                                                             off)));
    }
//ByteBufferAsIntBufferB 继承自 IntBuffer
 ByteBufferAsIntBufferB(ByteBuffer bb,
                                     int mark, int pos, int lim, int cap,
                                     int off)
    {

        super(mark, pos, lim, cap);
        this.bb = bb;
        offset = off;



    }
//IntBuffer
IntBuffer(int mark, int pos, int lim, int cap,   // package-private
             int[] hb, int offset)
{
    super(mark, pos, lim, cap);
    this.hb = hb; // null
    this.offset = offset;
}

// Creates a new buffer with the given mark, position, limit, and capacity
//
IntBuffer(int mark, int pos, int lim, int cap) { // package-private
    this(mark, pos, lim, cap, null, 0);
}

public final int[] array() {
    if (hb == null)
        throw new UnsupportedOperationException();
    if (isReadOnly)
        throw new ReadOnlyBufferException();
    return hb;
}
  1. abstract ByteBuffer compact()
    压缩。在 position 和 limit 之间的所有字节将会被拷贝到 缓冲区的开始处。即 position - limit 之间的数据整体前移到起始位,position 之前的数据将会被覆盖掉。
    position 不会被重置为0,而是为 the number of bytes copied

ByteBuffer byteBuffer = ByteBuffer.allocate(32);
byteBuffer.put((byte)1);
byteBuffer.put((byte)1);

print(Arrays.toString(byteBuffer.array()));
print("position = "+byteBuffer.position() + ", limit= "+byteBuffer.limit());
byteBuffer.compact();
print(Arrays.toString(byteBuffer.array()));
print("position = "+byteBuffer.position() + ", limit= "+byteBuffer.limit());
byteBuffer.put((byte)6);

print(Arrays.toString(byteBuffer.array()));

output

[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
position = 2, limit= 32
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
position = 30, limit= 32
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0]
//文档中给出的一个示例,这个是一个应用场景
buf.clear();          // Prepare buffer for use
while (in.read(buf) >= 0 || buf.position != 0) {
    buf.flip();
    out.write(buf);
    buf.compact();    // In case of partial write
}
  1. abstract ByteBuffer duplicate()
    重复,复印。重复一个新的 ByteBuffer ,需要注意的是,新的 ByteBuffer 和 旧的ByteBuffer 共享一个 backing array ,但是 position 不共享。
public ByteBuffer duplicate() {
        return new HeapByteBuffer(hb,
                                        this.markValue(),
                                        this.position(),
                                        this.limit(),
                                        this.capacity(),
                                        offset);
}
ByteBuffer byteBuffer = ByteBuffer.allocate(32);
byteBuffer.putChar('A');
ByteBuffer duplicateBuffer = byteBuffer.duplicate();
duplicateBuffer.putChar('S');
print("byteBuffer array = " + Arrays.toString(byteBuffer.array()));
print("duplicateBuffer array = " + Arrays.toString(duplicateBuffer.array()));
print("byteBuffer position = "+byteBuffer.position() );
print("duplicateBuffer position = "+duplicateBuffer.position());

output

byteBuffer array = [0, 65, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
duplicateBuffer array = [0, 65, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
byteBuffer position = 2
duplicateBuffer position = 4
  1. ByteBuffer get(byte[] dest, int offset, int length)
    将Buffer中的数据复制到目的数组中,这里的数组不共享。注意这里的 dest.length < remaining(),否则会抛出异常
ByteBuffer byteBuffer = ByteBuffer.allocate(32);
byteBuffer.putChar('A');
byteBuffer.putChar('B');
byteBuffer.rewind();
byte[] bytes = new byte[10];
byteBuffer.get(bytes,2, 2);
print(Arrays.toString(bytes));

output

[0, 0, 0, 65, 0, 0, 0, 0, 0, 0]
  1. get()/getChar()/getXXX()
    获取 buffer 中存储的数据,以特定的格式获取,position位置会改变。需要注意的是,读取的格式顺序应该和存入的顺序一致。这样才能保证数据的正确性。

  2. get(int index)/getChar(int index)/getXXX(int index)
    获取指定位置上的特定数据,position 位置不会改变。

ByteBuffer byteBuffer = ByteBuffer.allocate(32);
byteBuffer.putChar('A');
byteBuffer.putChar('B');
byteBuffer.putChar('C');
byteBuffer.putChar('D');
print(byteBuffer.getChar(0));
print(byteBuffer.getChar(2));

output

A
B
  1. boolean hasArray()
    是否有可用的 backing array 在调用 array()需要调用此方法来判断一下。
  2. put()/putChar()/putXXX()
    存入一个特定类型的数据,position 位置改变
  3. put(int index)/putChar(int index)/putXXX(int index)
    在指定位置上存入一个特定数据 position 位置不变。
ByteBuffer byteBuffer = ByteBuffer.allocate(32);
byteBuffer.putChar(3, 'A');
byteBuffer.putChar(4,'B');
print("byteBuffer position = " + byteBuffer.position());
print("byteBuffer array = " + Arrays.toString(byteBuffer.array()));

output

byteBuffer position = 0
byteBuffer array = [0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  1. abstract ByteBuffer slice()
    共用 backing array ,position 重置为 0, offset 为 this.position,capacity 为 this.remaining(), limit 为 this.remaining()
public ByteBuffer slice() {
    return new HeapByteBuffer(hb,
                                    -1,
                                    0,
                                    this.remaining(),
                                    this.remaining(),
                                    this.position() + offset);
}
  1. static ByteBuffer wrap(byte[] array, int offset, int length)
    生成一个 ByteBuffer ,这个构造方法通常是被用来“解析数据”。
    position = offset, limit = offset + length
 public static ByteBuffer wrap(byte[] array,
                                    int offset, int length)
 {
      try {
          return new HeapByteBuffer(array, offset, length);
      } catch (IllegalArgumentException x) {
          throw new IndexOutOfBoundsException();
      }
 }

 HeapByteBuffer(byte[] buf, int off, int len) { // package-private

        super(-1, off, off + len, buf.length, buf, 0);
        /*
        hb = buf;
        offset = 0;
        */




 }

  ByteBuffer(int mark, int pos, int lim, int cap,   // package-private
                 byte[] hb, int offset)
 {
      super(mark, pos, lim, cap);
      this.hb = hb;
      this.offset = offset;
  }

下一篇 将会写点有趣的东西

相关文章

  • java NIO---Buffer

    NIO中Buffer简介 java的NIO中buffer至关重要,buffer是读写的中介,主要和NIO的chan...

  • Buffer

    Java NIO Buffer当我们需要与NIO Channel进行交互时,我们就需要使用到NIO Buffer,...

  • NIO之三--Buffer

    Java NIO Buffer Basic Buffer Usage Buffer Capacity, Posit...

  • Java NIO Buffer

    Java NIO Buffer Buffer使用场景 Java NIO buffers 用于和Java chann...

  • NIO java编程

    NIO 同步式非阻塞式IO NIO组件:Buffer channel selector Buffer 缓冲区 1....

  • NIO(二、Buffer)

    目录 NIO(一、概述)NIO(二、Buffer)NIO(三、Channel)NIO(四、Selector) Bu...

  • NIO(四、Selector)

    目录 NIO(一、概述)NIO(二、Buffer)NIO(三、Channel)NIO(四、Selector) Se...

  • NIO(三、Channel)

    目录 NIO(一、概述)NIO(二、Buffer)NIO(三、Channel)NIO(四、Selector) Ch...

  • Netty之NIO

    ------NIO简介(1)-------- NIO组件 channel,buffer,selector,pip,...

  • Nio 缓冲类的基础---Buffer的flip,rewind,

    Nio 缓冲类的基础---Buffer的flip,rewind,clear等操作 nio的读写是要和Buffer的...

网友评论

    本文标题:Nio Buffer

    本文链接:https://www.haomeiwen.com/subject/bftuuftx.html