www.zhblog.net

Java NIO Buffer

与NIO Channel进行交互时,将使用Java NIO Buffer。前面提到过,数据从Channel读到Buffer,或从Buffer写到Channel。


缓冲区本质上是一个内存块,可以在其中写入数据,然后在以后再次读取。该内存块在NIO中封装成Buffer对象,该对象提供了一组方法,可以更轻松地使用该内存块。


1.Buffer的基本使用

使用Buffer读取和写入数据通常遵循以下四个步骤:

(1)写数据到 Buffer 

(2)调用buffer.flip() 

(3)从Buffer读取数据 

(4)调用buffer.clear() 或buffer.compact()


当你将数据写入缓冲区时,缓冲区会跟踪已写入多少数据。一旦需要读取数据,就需要调用flip()方法,将缓冲区从写入模式切换到读取模式。在读取模式下,缓冲区使你可以读取写入缓冲区的所有数据。


读取所有数据后,你需要清除缓冲区,以准备再次写入。你可以通过两种方式执行此操作:通过调用clear()或通过调用compact()。 clear()方法清除整个缓冲区。 compact()方法仅清除已经读取的数据。任何未读的数据都将移到缓冲区的顶部,并且现在写入到缓冲区的数据都将紧随其后。


一个简单的Buffer用法示例:

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();


2.Buffer Capacity,Position,Limit

一个Buffer需要熟悉三个属性,以便了解缓冲区的工作方式:

capacity

position

limit

position和limit的含义取决于缓冲区是处于读取模式还是写入模式。而capacity不管缓冲区模式如何,始终相同。


这是写和读模式下的capacity,position和limit的说明:

buffers-modes.png


Capacity

作为一个内存块,缓冲区具有一定的固定大小,也称为“容量”,你只能向缓冲区写入不超过容量的字节。一旦缓冲区已满,你需要先清空它(读取数据或清除它),然后才能向其中写入更多数据。


Position

当你将数据写入缓冲区时,你需要在特定位置position进行。最初的位置为0。将字节写入缓冲区后,该位置将前进以指向缓冲区中的下一个单元,位置最大为capacity-1。 从缓冲区读取数据时,也要从给定位置读取数据。当你将缓冲区从写入模式翻转到读取模式时,该位置将重置为0。从缓冲区读取数据时,你将从该位置进行读取,并且位置前进到下一个要读取的位置。


Limit

在写模式下,缓冲区的limit是可以写入缓冲区的数据量。在写模式下,limit等于缓冲区的容量。 将缓冲区切换到读取模式时,limit表示可以从数据中读取多少数据。因此,将Buffer切换到读取模式时,将limit设置为写入模式的position。换句话说,你可以读取与写入的字节一样多的字节(limit设置为写入的字节数,该字节数由position标记)。


3.Buffer 类型

Java NIO中有以下几个类型的缓冲区:

ByteBuffer

MappedByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

这些缓冲区代表不同的数据类型。换句话说,可以使用char,short,int,long,float或double代替缓冲区中的字节。

MappedByteBuffer有点特殊,后面单独介绍。


分配缓冲区

要获取Buffer对象,必须先分配它。每个Buffer类都有一个执行此操作的allocate()方法。

这是显示容量为48个字节的ByteBuffer分配的示例:

ByteBuffer buf = ByteBuffer.allocate(48);


这是一个分配了1024个字符的CharBuffer示例:

CharBuffer buf = CharBuffer.allocate(1024);


写数据到Buffer

你可以通过两种方式将数据写入Buffer:

将数据从Channel写入Buffer ; 

通过Buffer的put()方法将数据写入Buffer;

这是一个示例,显示Channel如何将数据写入Buffer:

int bytesRead = inChannel.read(buf); //read into buffer.


这是一个通过put()方法将数据写入Buffer的示例:

buf.put(127);  


put()方法还有许多其他版本,允许你以多种不同方式将数据写入Buffer中。例如,在特定位置写入或将字节数组写入到缓冲区。有关更多详细信息,请参见JavaDoc。


flip()

flip()方法将Buffer从写入模式切换到读取模式。调用flip()会将position重置为0,并将limit设置为原来的position。换句话说,position现在标记了读取位置,而limit标记了有多少字节可写入缓冲区。


从Buffer读数据

你可以通过两种方式从缓冲区读取数据

从缓冲区读取数据到Channel。

使用get()方法从缓冲区读取数据。

这是如何从缓冲区将数据读取到Channel的示例:

//read from buffer into channel.

int bytesWritten = inChannel.write(buf);


这是使用get()方法从Buffer读取数据的示例:

byte aByte = buf.get();


get()方法还有许多其他版本,允许多种不同方式从Buffer读取数据。例如,在特定位置读取或从缓冲区读取字节数组。有关更多详细信息,请参见JavaDoc。


rewind()

Buffer.rewind()将position设置回0,因此可以重新读取Buffer中的所有数据。limit保持不变,因此仍标记可以从缓冲区读取多少个字节。


clear() 和 compact()

一旦完成了从缓冲区中读取数据的操作,则必须使缓冲区准备好再次写入。可以通过调用clear()或通过调用compact()来实现。

如果调用clear(),则position将重新设置为0,limit重新设置为capacity。换句话说,缓冲区被清除,缓冲区中的数据未清除。只标记从哪里开始写入数据。

如果在调用clear()时缓冲区中有任何未读取的数据,则该数据将被“遗忘”,这意味着你将不再具有任何标记来读取那些尚未读取的数据。

如果缓冲区中仍然有未读取的数据,并且你想稍后再读取,但是现在需要先进行一些写入操作,请调用compact()而不是clear()。

compact()将所有未读数据复制到Buffer的头部。然后将位置设置在最后一个未读元素之后。就像clear()一样,limit属性仍然设置为capacity。现在,缓冲区已准备好写入,但是不会覆盖未读取的数据。


mark() 和 reset()

你可以通过调用Buffer.mark()方法在Buffer中标记位置。然后,可以稍后通过调用Buffer.reset()方法将位置重置回前面标记的位置。例:

buffer.mark();



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



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


4.equals() 和 compareTo()

可以使用equals()和compareTo()比较两个缓冲区。


equals()

如果两个缓冲区相等,则:

它们具有相同的类型(字节,字符,整数等)

它们在缓冲区中具有相同数量的剩余字节,字符等。

所有剩余的字节,字符都是相等的。

equals仅比较Buffer的一部分,而不比较其中的每个元素。实际上,它只是比较缓冲区中的存在的元素。


compareTo()

compareTo()方法比较两个缓冲区的其余元素(字节,字符等),一般用于排序。在以下情况下,一个缓冲区被认为比另一个缓冲区“小”:

Buffer中的第一个元素比另一个Buffer中第一个元素小。

所有元素都相等,但是第一个缓冲区元素少于第二个缓冲区的元素。


总结:

我认为 NIO Buffer 中以上内容是最重要的!


 

展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情