图解ByteBuffer
可惜Android中没有像Objective-C中那样强大NSData类型,不过无所谓,至少还有ByteBuffer可以用,不过感觉ByteBuffer虽然看起来简单,但是实际用起来还是需要涉及一些概念,因此这里主要解释一下ByteBuffer的一些主要方法。
ByteBuffer主要标志位说明
标志位 | 初始值 | 说明 |
---|---|---|
mark | -1 | 标记位 |
position | 0 | 当前位置 |
limit | 指定的缓冲区容量 | 已写入有效数据容量 |
capacity | 指定的缓冲区容量 | 缓冲区容量 |
ByteBuffer的初始化
ByteBuffer提供两种不同的构造函数,其本质主要是构建的ByteBuffer类型不同,其中一种构造函数参照源代码:
1 | //第一种,分配的是DirectByteBuffer |
详细两种不同类型的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操作,仍然可以将数据获取出来。直观的话,可以直接看源代码:1
2
3
4
5
6public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
Slice操作
slice方法的作用,就是做数据分割,将当前的position到limit之间的数据分割出来,返回一个新的ByteBuffer,同时,mark标记重置为-1。不过这里注意,分割出来的数据的容量刚好就是数据长度,而不是被分割之前的长度。
快速清除已读取的数据
有时候,我们只是想要去掉前面一部分,而保留后面一部分数据,同时保持缓冲区的大小不变呢,这里提供一种思路,如下:
1 | public void clearPrePositionData(ByteBuffer byteBuffer) { |