http://tutorials.jenkov.com/java-nio/buffers.html
还可以看
Java缓冲区(Buffers )与通道(Channels)同时使用。正如我们所了解的,数据从通道(Channels)读入到缓冲区(Buffers ),从缓冲区(Buffers )写入到通道(Channels)。
缓冲区(Buffers )本质上是一个内存块,可以在里面写入,然后从里面读取。内存块并包装成NIO buffer对象,并有提供一系列方法使操作内存块变的简单。
一系列的NIO buffer主题如下:
- Basic Buffer Usage(基本缓冲区使用)
- Buffer Capacity, Position and Limit(缓冲区Capacity, Position and Limit )
- Buffer Types(缓冲区类型)
- Allocating a Buffer(分配缓冲区)
- Writing Data to a Buffer(写入缓冲区)
- flip()
- Reading Data from a Buffer(从缓冲区读取数据)
- clear() and compact()
- mark() and reset()
- equals() and compareTo()
Basic Buffer Usage(基本缓冲区使用)
使用一个缓冲区来读取和写入数据,通常遵循以下四个步骤:
1:Write data into the Buffer(数据写入缓冲区)
2:Call buffer.flip()(调用flip方法)
3:Read data out of the Buffer(从缓冲区读取数据)
4:Call buffer.clear() or buffer.compact()(调用clear或compact方法)
当数据写入缓冲区(buffer),缓存区维持跟踪多少数据已经被写入。一旦需要读取数据,调用flip方法,将缓冲区由从写模式转换至读模式。读模式允许将所有已经写入的数据读取出来。
在数据读取完毕后,应该清空缓冲区保证缓冲区做好写的准备,可以按两种方式处理:调用clear()方法或调用 compact()
方法,clear()方法清空整个的缓冲区(buffer),compact()方法仅仅清空你已经读取的数据,未读取的数据将被移动至缓冲区的开始位置,新写入的数据将写缓冲区(buffer)在未读取数据的后面。
简单的Buffer使用的例子,包含with the write, flip, read 和 clear 操作:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
//create buffer with capacity of 48 bytes
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf); //read into buffer.
while (bytesRead != -1) {
buf.flip(); //make buffer ready for read
while(buf.hasRemaining()){
System.out.print((char) buf.get()); // read 1 byte at a time
}
buf.clear(); //make buffer ready for writing
bytesRead = inChannel.read(buf);
}
aFile.close();
Buffer Capacity, Position and Limit
缓冲区(Buffers )本质上是一个内存块,可以在里面写入,然后从里面读取。内存块并包装成NIO buffer对象,并有提供一系列方法使操作内存块变的简单。
为更好的了解缓冲区是怎么工作,缓冲区(buffer)包含3个熟悉必须熟悉:
1:capacity(容量)
2:position(位置)
3:limit(限制)
position与limit 意义取决于缓冲区是读模式还是写模式。Capacity在任何模式下是一样的含义。
下图将图示说明读写模式下的capacity, position and limit ,详细的说明将图示后面。
Capacity(容量)
作为一个内存块,缓冲区有固定的大小,也被称作“容量”,你只能写入容量大小的bytes, longs, chars等,一单缓冲区满了,如果要写入新的数据到缓冲区,必须清空它(读取,或clear)。
Position(位置)
你必须在特定的位置将数据写入缓冲区,初始Position的值为0,当byte, long被写入到缓冲区时,Position将增长并指上下个将插入数据的单元,Position最大值能到Capacity-1;
从缓冲区读取数据时你也要给个Position,缓冲区从写模式切换到读模式时,Position将重新被设置回0。读取缓冲区数据也是从Position开始读取,然后Position将增长并只上下一个读取的位置。
Limit(限制)
写模式下Limit表示你可以写多少数据到缓冲区,在写模式下Limit等于缓冲区的Capacity。
缓冲区切换至读模式,Limit表示你可以从缓冲区里读取多少个数据。因此,当缓冲区切换至读模式,Limit的值为写模式下的Position的值,换句话说,你可以读到与写一样多的数据(Limit的值写入缓冲区的自己数,被Position给标记的)。
Buffer Types(缓冲区类型)
Java的NIO以下缓冲区类型有以下几种:
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
正如你所见,这些缓冲区代表不同的数据类型,它们可以让你可以使用char, short, int, long, float or double代替byte。
MappedByteBuffer有点特殊,将在后续的文章中提到。
Allocating a Buffer(分配一个缓冲区)
为获取到一个缓冲区对象你必须首先分配,每个buffer类都有allocate方法完成分配,下面代码显示的是分配一个容量为48字节的ByteBuffer。
ByteBuffer buf = ByteBuffer.allocate(48);
下面代码为1024个字符CharBuffer
CharBuffer buf = CharBuffer.allocate(1024);
Writing Data to a Buffer(写数据到缓冲区)
两种方式写数据到缓冲区(buffer)
1:从通道(Channel)里面写数据到缓冲区。
2:使用Buffer的put方法
通道写入buffer的代码如下:
int bytesRead = inChannel.read(buf); //read into buffer.
使用Buffer的put方法代码如下:
buf.put(127);
存在各种put()方法,允许你以各种方式将数据写入到缓冲区里面。例如:写特殊的positions或字节数组到buffer。具体的buffer实现更多详细信息,请参阅Javadoc。
flip( )
flip方法将buffer从写模式切换到读模式,调用flip将Position设置回0,将Limit设置为Position的值。
换种说法,Position标示的读的位置,Limit标示的多少个bytes, chars等已经被写入到buffer中,同时也代表可以从buffer读取多少个bytes, chars等。
Reading Data from a Buffer(从buffer里面读取数据)
两种方式能从buffer里读取数据:
1:将数据从buffer读取到Channel(通道)。
2:使用get方法读取。
将数据从buffer读取到Channel(通道)代码如下:
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);
使用get方法读取代码如下:
byte aByte = buf.get();
存在各种get()方法,允许你以各种方式将数据从缓冲区里面读取数据。例如:读特殊的positions或字节数组。具体的buffer实现更多详细信息,请参阅Javadoc。
rewind()
Buffer.rewind()将Position设置回0,因此你可以重新从buffer里面读取数据。Limit未受影响,它任然标记buffer中能读取的元素个数。
clear() and compact()
一旦你完成读取数据的buffer,你可以调用clear() 或compact()使缓冲区准备再次写。
调用clear() 方法,Position将被设置为0且Limit被设置为Capacity,实际上buffer清空,数据是没有清空的,仅仅标示你可以从哪里开始写入数据。
没有任何可读取的数据在buffer中,调用clear()方法,数据将被‘遗忘’,这意味着你不再有任何标记,告诉什么样的数据被读取,什么也没有被读取。
buffer中存在未读取完毕且在以后会使用的数据,如果马上要往buffer写入数据,使用compact()代替clear().。
compact()方法将buffer中未读取的数据拷贝到buffer的最前面,并将Position设置在最后的元素的后面,Limit任然是Capacity,如clear()方法类似。buffer将可以再次写入,并不会覆盖未读取的数据。
mark() and reset()
mark()你可以标记buffer一个给定位置。然后你可以调用reset()方法将位置回退到你原来标记的位置。
例子如下:
buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset(); //set position back to mark.
equals() and compareTo()
两个buffer的比较实用equals() 和compareTo()
equals()
两个buffer相等满足以下条件:
1:它们有数据相同的类型。
2:buffer 剩余元素的数目相等。
3:buffer中剩余元素也一一相等。
equals()仅仅比较buffer的一部分,即在buffer中剩下的元素,而不是它里面所有的元素。
compareTo()
compareTo()方法比较两个buffer的剩余元素,用于排序的情况下,一个buffer比另外一个buffer小情况如下:
1.第一个buffer的元素小于另外buffer对应位置元素。
2.所有元素相等,但是第一个buffer消耗的比第二块(及缺少元素个数)