Buffer是什么
和它的名字一样,Buffer是一个缓冲区,本质上是一块可以写入数据。可以读取数据的内存。在NIO中,Buffer用于和NIO中的各种channel交互。数据可以从channel中读入Buffer,然后从Buffer中写入另一个channel。
Buffer中几个重要的概念
capacity:容量,指定之后不可变动
limit:限制,第一个不应该读取或写入数据的索引,初始时和capacity在一个位置。
position:位置,下一个可读取或写入的位置,初始为0,不能为负,且不能大于limit
举几个例子来说明Buffer运作方式
初始时,即刚分配
1
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
其状态图如下:
当写入几个值时
1
2
3
4byteBuffer.put((byte)1);
byteBuffer.put((byte)2);
byteBuffer.put((byte)3);
byteBuffer.put((byte)4);状态如下
当写入了数据进入缓冲区时,就可以读取数据,在上面说过,数据写入和读取的下一个位置是position,可是现在position在索引为4(数组下标从0开始,这里缓冲区是一个byte数组)如何读取呢。这里就要介绍一下Buffer缓冲区有两种状态,即读和写,在读的状态下,不能做写入操作,同样在写状态下也不能做读操作,否则缓冲区会数据会被破坏。在buffer中提供了flip()来切换读写状态。当调用flip()函数,缓冲区状态由写入变成读取。
可以看到,limit移动到position位置,而position移动到索引0位置。可以从Buffer源码中看到这个操作。
1
2
3
4
5
6public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}此时进入读状态开始读取数据,如下图
当读取到一半时,这个时候想写数据怎么办,我们知道flip()函数可以切换读写状态,但是position会从0开始,也就是说我们没有读完的数据会被后来写入的数据覆盖。所以这个时候不能用flip()函数来切换,ByteBuffer提供了另外一个函数compact(),该函数会将未读完的数据复制到索引0位置开始,将position和limit之间的数据依次复制,然后limit移动到capacity位置。如下图
以ByteBuffer为例写一个Demo
1 | public class TestBuffer { |
运行结果:
1 | 第一次读取:1 |