JAVA NIO简明教程 四 Buffer缓冲

JAVA NIO简明教程 四 Buffer缓冲

JAVA NIO Buffer通常和channels一起使用。你已经知道数据通常从channels写入buffers,或者从buffers写入channels.

一个buffer本质上是一块内存的映射,能够读数据,之后再次写入数据。内存快被包裹在nio buffer object(译者注:本质是一个byte数组),buffer提供一系列的方法是你能够很方便的操作内存块。

Buffer的基本使用

使用Buffer去读写数据一般需要经过下面四个步骤:

  1. 写数据到Buffer
  2. 调用buffer.flip()
  3. 从Buffer读数据
  4. 调用buffer.clear() 或者 buffer.compact()

当你写数据进入缓冲区的时候,缓冲区能够记录有多少数据被写入。一旦你需要读数据,你需要使buffer从写模式切换到读模式依赖flip()方法。在读模式缓冲区能让你读所有的数据写入缓存。

一旦你读完了所有的数据,你需要清除buffer,使缓冲区能够再一次被写入,你能使用两种方式:调用

  1. clear() 2. compact(). clear()方法能够清楚整个缓冲区。compact()方法仅仅只能清除已经读取的数据,一些还没有被读取的数据被移动到缓冲区的开始部分,正在写入的数据将在未读数据之后。

下面是一个简单的Buffer示例,展示了 写、读、flip、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();

缓冲区的capcity、Position、Limit

缓冲区实质上是一块能够读写数据的内存。内存被包裹在一个nio buffer 对象,并且提供了一系列的方法使你能很方便的操作内存。

一个缓冲区有三个重要的你必须了解熟悉的属性,能够使你了解缓冲区是如何工作的:

  • capacity
  • position
  • limit

postion和limit的意义依赖于缓冲区是读模式还是写模式,Capacity不论何种模式,都是表示缓冲区的容量。

下图展示了position、limit、capacity在读写模式下的区分。

buffers-modes

(译者注:在写模式下:limit和capacity意义一样表示可写的内存极限,position指向当前已经写到了那块内存,初始指向0,最大limit/capacity)
(译者注:在读模式下: limit表示本次可读的最大极限,position表示当前读到了那一块内存,limit到capacity表示可写的内存)

Capacity

创建一个缓冲区的时候实际上创建的是一块内存,固定大小的内存,意味着你仅仅只能写入capacity大小的字节、长整型、字符等。一旦缓冲区已满,如果你想要继续写数据,需要读取缓冲区中的数据或者直接清除缓冲区中的数据。

Position

当你写入数据到缓冲区,position将被移动。position初始化为0,当你写入一个字节、长整型到缓冲区,position将被移动指向下个内存单元,注意position最大是capacity-1.

Limit

缓冲区在写模式下,limit表示缓冲区能够写入多少数据,和capacity的大小是一样的。
当在读模式下,表示最大可读多少数据。

缓冲区类型

java nio提供了下面几种缓冲区类型:

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

从上面可以看到,这些缓冲区表示不同的数据类型。这些类型可以使用使用char,short,int,long,float,double的缓冲区类型。

MappedByteBuffer是比较特殊在后续的章节会说明。(译者注:用来操作大文件)

分配一个缓冲区

要获得Buffer对象,你必须先分配给它一定的大小。每一个Buffer类有一个allocate()方法来分配大小。下面是一个示例,分配了48字节的大小的缓冲区。

    ByteBuffer buf = ByteBuffer.allocate(48);

下面是一个示例,分配了1024字符大小

    CharBuffer buf = CharBuffer.allocate(1024)

写入数据到缓冲区

你能写数据到缓冲区通过下面两种方式:

  1. 写数据从channel到buffer
  2. 通过调用buffer的put等方法来写入

下面是一个示例,如何从channel写入数据到buffer

    int byteRead = inChannel.read(buf);

下面示例通过使用put方法来说明如果写入数据到缓冲区:

    buf.put(127);

put方法被重载了很多次,允许你通过不同的方式写入数据到缓冲区。例如:写入指定的位置,或者写入数组字节,查看缓冲区的相关实现的javaDoc查看更加详细的说明。

flip()

flip()方法使缓冲区从写模式转为读模式。当调用了filp方法后position被重置为0,limit被设置为position之前的值(表示之前写模式写入多少数据)。

从缓冲区读数据

有两种方式能够从缓冲区读数据

  1. 从缓冲区读数据写入channel
  2. 你也可以使用get方法来从缓冲区读数据

下面是一个示例,展示如何读数据从缓冲区写入到channel

int bytesWritten = inChannel.write(buf);

下面的示例,展示如何使用get方法从缓冲区读数据

    byte aByte = buf.get();

get有许多版本的重载方法,允许你从指定位置、字节数组读取缓冲区。

rewind()

调用rewind方法,使position重置为0,是你能重复的读取缓冲区中的数据。

clear()和compact()

一旦读完缓冲区中的数据后,你必须保证缓冲区能够被再次写入,你能够调用clear和compact方法来调整position,limit.

当你调用clear方法position将被设置为0,limit被设置为等于capacity。看起来缓冲区的数据被清除了,实际上数据并没有清楚,只是调整了positon、limit是缓冲区能够被再次写入覆盖之前的数据,即使数据没有被读取。

如果有未读的数据,你并不想他们被覆盖,那么你可使用compact方法代替clear方法。

compact将拷贝所有未读的数据放在缓冲区的开始位置,position也并不会被设置为0,而是未读的数据长度,limit等于capacity和clear方法的效果一样,缓冲区可以再次被写入,但是不用担心会覆盖之前的数据。

mark()和reset()

你能移动position使用buffer的mark方法。在mark方法之后,你可以调用reset方法来复位position。下面是一个示例.

    buffer.mark();
    //call buffer.get() a couple of times, eg. during parsing.
    buffer.reset(); // set position back to mark 

equals() 和 compareTo()

很有可能有时需要比较两个缓冲区使用equals和compareTo().

equals()

比较两个缓冲区是否相等:

  1. 是否类型相同(byte,char,int等等)
  2. 缓冲区中是否剩余的字节、字符大小相同
  3. 所有剩余的字节是否相同

从上面可以看到缓冲区比比较相等仅仅比较的是缓冲区的一部分,而不是缓冲区的所有字节,事实上比较大小仅仅比较缓冲区剩余的部分。

compareTo()

compareTo方法用来排序的时候,比较两个缓冲区中剩余的部分(字节、字符等等),
一个缓冲区小于另一个缓冲区是因为下面的比较条件:

  1. 第一个元素等于小于另一个缓冲区中对应的元素。
  2. 所有的字节都是相等的,但是第一个缓冲区在第二个缓冲区之前耗尽了元素。
发布了121 篇原创文章 · 获赞 56 · 访问量 167万+

猜你喜欢

转载自blog.csdn.net/u013565163/article/details/83625714