Java Nio 四、Java NIO Buffer

最后更新时间:2014-06-23


Java NIO Buffers当与NIO Channels相互作用的时候会被使用。正如你知道的,数据时从channels写到buffers,以及从buffers写入channels。

一个buffer实际上是一块你可以写进数据的内存,这个你可以稍后再读取。这个内存块是用一个NIO buffer的对象包装成的,这个对象提供了许多方法,使得与内存块一起工作更简单些。


基本的Buffer使用


使用一个Buffer去读写数据,典型的如下很小的四步过程:

  1. 写数据到Buffer
  2. 调用buffer.flip()
  3. 从buffer中读出数据
  4. 调用buffer.clear() 或者 buffer.compact()
当你写数据进入buffer的时候,这个buffer将会跟踪有多少数据你已经写入了。一旦你需要读取这个数据,你需要调用flip()方法将这个buffer由写模式转换为读模式。在读模式下,这个buffer可以使你读取所有写入到buffer的数据。
一旦你读取了所有的数据,你需要清空这个buffer,使他准备再次写,你有两种方法可以做这个:通过调用clear()或者调用compact()方法。这个clear方法是清空整个buffer,这个compact方法只是清空你已经读取的数据,任何未读的数据将会移动到buffer的开始位置,并且新的数据将会写到未读取数据的后面。
这里有一个简单使用buffer的例子,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.<strong>read</strong>(buf); //read into buffer.
while (bytesRead != -1) {

  buf.<strong>flip</strong>();  //make buffer ready for read

  while(buf.hasRemaining()){
      System.out.print((char) buf.<strong>get</strong>()); // read 1 byte at a time
  }

  buf.<strong>clear</strong>(); //make buffer ready for writing
  bytesRead = inChannel.<strong>read</strong>(buf);
}
aFile.close();

Buffer的容量,位置和限制

一个buffer实际上是一块你可以写进数据的内存,这个你可以稍后再读取。这个内存块是用一个NIO buffer的对象包装成的,这个对象提供了许多方法,使得与内存块一起工作更简单些。
为了理解Buffer是怎么工作的,你需要熟悉Buffer的三个属性。他们分别是:
  • capacity
  • position
  • limit
这个position和limit的含义依赖这个Buffer是在读模式还是写模式下。不管是在读模式还是写模式,capacity的含义总是一样的。
这里有一个capacity,position,和limit在写模式和读模式的一个图解。解释是在这个图解的后面。

Capacity

对于现有的一个内存块,一个Buffer有一个固定的大小,也称他为”capacity“。你可以只是写这个容量的bytes,long,chars等等进入到Buffer。一旦这个buffer满了,你需要清空他(读数据或者清空他)在你写更多的数据进去之前。

Position
当你写数据进入到Buffer的时候,你可以在一个确定的位置做这个。最初的,这个position的值是0。当一个byte,long型的数据写入到buffer的时候,这个position将会提前指向到这个buffer下一个单元去插入数据。position的最大值为capacity - 1。
当你从一个buffer中读取数据的时候,你也可以从一个给予的position处读取数据。当你反转一个buffer从写模式到读模式的时候,这个position将会重新置为0。就像你从一个buffer中指定的位置读数据是一样的,并且position提前到下一个位置去读取。

Limit
在写模式下,一个buffer的limit是限制有多少数据可以写到buffer。在写模式下,这个limit等于这个buffer的capacity。
当反转这个buffer进入到读模式的时候,limit意味着限制有多少数据可以从这个数据中读取。因此,当反转一个buffer进入到读模式的时候,limit就会设置为写模式下的写的position。换句话说,你可以读取和写一样多的字节(limit被设置成被写字节的数量,这个是被position标记的)

Buffer Types
Java NIO自带以下的Buffer类型:
  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
正如你看到的,这些Buffer类型呈现着不同的数据类型。换句话说,他们使得你在buffer中与字节共事代替为使用char,short,int,long,float,或者double来操作数据。
这个MappedByteBuffer是个专用的比特(bit)操作,他将会在他自己的章节中讲解。

分配一个Buffer
为了获得一个Buffer对象,你必须首先分配他。每一个Buffer类都有一个allocate()方法做这个分配的事情。这里有一个例子显示了一个有48字节容量的ByteBuffer的分配:
ByteBuffer buf = ByteBuffer.allocate(48);

这里有一个例子,是一个分配了1024个字符空间的CharBuffer:
CharBuffer buf = CharBuffer.allocate(1024);

写数据到Buffer
你可以使用两种方式写数据到Buffer:
  1. 从一个Channel中写数据进入Buffer。
  2. 自己写数据进入Buffer,通过buffer的put()方法。
这里有一个例子,是一个Channel怎样写数据进入到Buffer:
int bytesRead = inChannel.read(buf); //read into buffer.

这里有一个例子,是Buffer通过调用buffer的put()方法写数据进入Buffer:
buf.put(127); 

这里有许多put方法的其他版本,用许多不同的方式允许你写数据到Buffer。例如,可以在特定的位置写数据,或者直接写一个字节数组进入buffer。看JavaDoc可以看到更具体更详细的buffer实现。

flip()
这个方法是将一个Buffer从写模式切换到读模式。调用flip()方法设置这个position的值为0,以及设置这个limit的值为刚才position的值。
换句话说,position现在标记了读的位置,limit标记了有多少个Buffer的字节,字符等等被写入到buffer。限制有多少个字节,字符可以去读取的。

从Buffer中读取数据
这里有两种方式你可以从Buffer中读取数据。
  1. 从buffer中读取数据到channel.
  2. 从buffer自身读取数据,使用get()方法中的一个.
这里有一个从buffer读数据到channel的例子:
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);

这里有个通过buffer的get方法读取数据的例子:
byte aByte = buf.get();   

这里有许多get方法的其他版本,允许你用许多不同的方式从buffer中读取数据。例如,在指定的位置读取,或者从一个buffer中读取一个字节数组。看JavaDoc可以看到更具体更详细的buffer实现。

rewind()
这个Buffer.rewind()方法重新设置为position为0,以至于你可以读取buffer中的所有数据。这个limit是保持未改变的,因此仍然标记着有多少个元素(字节,字符等)可以从Buffer中读取。

clear()和compact()
一旦你已经从Buffer中读取出数据了,你不得不使得这个buffer再次准备去写。你可以调用clear()方法或者compact()方法去做这个。
如果你调用clear方法,这个position的值将会被设置为0,这个limit的值是capacity的值。换句话说,这个buffer被清空了。在这个buffer中的数据还没有被清空,只是这个标记告诉你在哪个位置可以往buffer里面写数据。
当你调用clear方法的时候,这里有任何未被读取的数据,这些数据将会”忘掉“,丢失,意味着你不再有任何的标记告诉你已经读取到什么数据了,没有读取到什么数据。
如果在buffer中仍然有未读取的数据,并且你想稍后读取,但是你需要首先做一些写的事情,调用compact方法代替clear方法。
compact方法拷贝所有未读取的数据到buffer的开端。然后设置position的值刚好为最后未读取数据元素的后面。这个limit的值仍然等于capacity,就像clear一样。现在这个buffer准备好写了,但是你不会覆盖为读取的数据。

mark()和reset()
通过调用Buffer.mark()方法,你可以在buffer中标记一个给予的位置。通过调用Buffer.reset方法你然后就可以稍后设置这个position的值为之前你标记的位置。这里有一个例子:
buffer.mark();

//call buffer.get() a couple of times, e.g. during parsing.

buffer.reset();  //set position back to mark.  

equals()和compareTo()
使用equal()方法和compareTo()方法比较两个buffer是可能的。
equals()
两个buffer是相同的,如果:
  1. 他们有相同的类型(byte,char,int等等)。
  2. 他们在buffer中剩余的字节,字符等等数量相同。
  3. 所有剩余的字节,字符等等是相等的。
正如你所看到的,相等只是比较了buffer的部分,不是里面的每一个单独的元素。实际上,它只是比较了buffer中的剩余的元素。
compareTo()
这个compareTo方法比较两个buffer中剩余的元素(字节,字符等等),举例说,在排序中会使用。一个buffer认为比另一个buffer小如果:
  1. 第一个元素与另外一个buffer中对应的元素不相等,而是比他小。
  2. 所有的元素是相同的,但是第一个buffer在第二个buffer之前耗尽了所有的元素(它有更少的元素)。

翻译地址:http://tutorials.jenkov.com/java-nio/buffers.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值