Java NIO中的Buffer用于和NIO通道进行交互。
NIO中数据是从通道读入缓冲区,从缓冲区写入到通道中的。缓冲区本质上是一块可以写入数据,可以读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
Buffer的基本用法
使用Buffer读写数据一般遵循以下四个步骤:
- 写入数据到Buffer
- 调用
flip()
方法 - 从Buffer中读取数据
- 调用
clear()
方法或者compact()
方法
当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。
读完缓冲区中所有数据后,需要清空缓冲区,让它可以再次被写入。其清空方式有两种:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已读数据,未读数据会被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
使用Buffer的例子:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); //创建容量为48字节的缓冲区 ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); //读入缓冲区 while (bytesRead != -1) { buf.flip(); //使缓冲区准备好读取 while(buf.hasRemaining()){ System.out.print((char) buf.get()); // 一次读取1个字节 } buf.clear(); //使缓冲区准备好写 bytesRead = inChannel.read(buf); } aFile.close();
Buffer的capacity,position和limit
Buffer的三个属性:
- capacity
- position
- limit
capacity
作为一个内存块,Buffer有一个固定的大小值“capacity”,你只能往里写capacity个byte、long,char等类型。一旦Buffer写满,需要将其清空才能继续写数据往里写数据。
position
写数据到Buffer中时,position表示当前位置,初始值为0,最大值可为capacity – 1。当一个数据写入到Buffer后, position会移动到下一个可插入数据的Buffer单元。
将Buffer从写模式切换到读模式,position会被重置为0。当从Buffer读取一个数据后,position会向前移动到下一个可读的位置。
limit
在写模式下limit等于Buffer的capacity,limit表示你最多能往Buffer里写入多少数据。
当切换Buffer到读模式时,limit会被设置成写模式下的position值, 表示最多能读到多少数据。
Buffer的类型
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
Buffer类型代表了不同的数据类型。通俗讲就是可以通过char,short,int,long,float 或 double类型来操作缓冲区中的字节。
Buffer的分配
要想获得一个Buffer对象首先要进行分配。 每一个Buffer类都有一个allocate方法。
ByteBuffer buf = ByteBuffer.allocate(
48
);//分配48字节capacity的ByteBuffer
CharBuffer buf = CharBuffer.allocate(
1024
);//分配一个可存储1024个字符的CharBuffer
向Buffer中写数据
写数据到Buffer有两种方式:
- 从Channel写到Buffer。
- 通过Buffer的put()方法写到Buffer里。
从Channel写到Buffer中:
int bytesRead = inChannel.read(buf); //读入缓冲区
通过put方法写Buffer中:
buf.put(
127
);
注:put方法有很多版本,允许以不同的方式把数据写入到Buffer中。
从Buffer中读取数据
从Buffer中读取数据有两种方式:
- 从Buffer读取数据到Channel。
- 使用get()方法从Buffer中读取数据。
从Buffer读取数据到Channel中:
int bytesWritten = inChannel.write(buf);//从缓冲区读入通道
使用get()方法从Buffer中读取数据:
byte
aByte = buf.get();
注:get方法有很多版本,允许以不同的方式从Buffer中读取数据。例如,从指定position读取,或者从Buffer中读取数据到字节数组。
flip()方法
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
rewind()方法
Buffer.rewind()方法会将position设回0,这样可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素。
clear()与compact()方法
Buffer中的数据读完后,需要让Buffer准备好再次被写入。这可以通过clear()或compact()方法来完成。
调用clear()方法,未读数据将“被遗忘”,position将被设回0,limit被设置成 capacity的值。此时的Buffer 被清空,Buffer中的数据并未清除,写入数据时会覆盖未读数据。
compact()方法将所有未读的数据拷贝到Buffer起始处。position设到最后一个未读元素后面,limit属性依然设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
mark()与reset()方法
调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后调用Buffer.reset()方法即可恢复到这个position。
例如:
buffer.mark(); //例如在解析期间多次调用buffer.get() buffer.reset(); //设定位置回到标记.
equals()与compareTo()方法
可以使用equals()和compareTo()方法比较两个Buffer。
注:剩余元素是从 position到limit之间的元素
equals()方法
当满足下列条件时,表示两个Buffer相等:
- 有相同的类型(byte、char、int等)。
- Buffer中剩余的byte、char等的个数相等。
- Buffer中所有剩余的byte、char等都相同。
equals只比较Buffer中的剩余元素,不是比较每一个在它里面的元素。
compareTo()方法
如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:
-
- 第一个不相等的元素小于另一个Buffer中对应的元素 。
- 所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。