Buffer
Buffer 是一种特殊元数据类型的容器,是线性有序的序列。Buffer 是一个抽象类,它定义一系列的通用方法。其子类有
ByteBuffer、CharBuffer、IntBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer
Buffer 中重要的几个属性是
- capacity
Buffer 中 backing array 的 length ,即Buffer 的容量。 - limit
Buffer 中 的可读取数据的范围,limit 到 capacity 之间的数据不可读 - position
Buffer 中可操作数据的位置。 - mark
Buffer 中的标记位,通常与 reset() 方法一起使用。
0<=mark<=position<=limit<=capacity
重要的方法
- clear()
为存放新数据做好准备,position = 0,limit = capacity - flip()
为获取数据做好准备,limit = position, position = 0 - 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
- 实例化方法
- ByteBuffer.allocate(int capacity)
- ByteBuffer.allocateDirect(int capacity)
- ByteBuffer.wrap(byte[] array)
- ByteBuffer.wrap(byte[] array, int offset, int length)
- 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]
- 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);
}
- 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;
}
- 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
}
- 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
- 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]
-
get()/getChar()/getXXX()
获取 buffer 中存储的数据,以特定的格式获取,position位置会改变。需要注意的是,读取的格式顺序应该和存入的顺序一致。这样才能保证数据的正确性。 -
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
- boolean hasArray()
是否有可用的 backing array 在调用 array()需要调用此方法来判断一下。 - put()/putChar()/putXXX()
存入一个特定类型的数据,position 位置改变 - 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]
- 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);
}
- 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;
}
网友评论