当前位置: 首页 > 教程 > Java NIO >

Java NIO 缓冲区

精华
小牛编辑
158浏览
2023-03-14

与NIO通道进行交互时,将使用Java NIO缓冲区。如您所知,数据从通道读取到缓冲区,然后从缓冲区写入通道。

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

1 Buffer的基本使用

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

  1. 将数据写入缓冲区
  2. 调用buffer.flip()方法
  3. 从缓冲区读取数据
  4. 调用buffer.clear()或buffer.compact()方法

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

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

以下一个简单的Buffer用法示例:

/**
 * 小牛知识库网: https://www.xnip.cn
 */
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的容量、位置、限制

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

Buffer对象具有三个您需要熟悉的属性,以了解其Buffer工作原理。分别是:

  • 容量(capacity)
  • 位置(position)
  • 限制(limit)

位置和限制取决于是否Buffer对象在读或写模式。不管缓冲模式如何,容量始终意味着相同。

下图说明写和读模式下的容量,位置和限制的说明。

写入和读取模式下的缓冲区容量,位置和限制。

2.1 容量

作为存储块,Buffer具有一定的固定大小,也称为其“容量”。您只能将capacity字节,long,char等写入缓冲区。缓冲区装满后,需要先清空(读取数据或清除数据),然后才能向其中写入更多数据。

2.2 位置

将数据写入Buffer时,您需要在特定位置进行。最初,该位置为0。将byte,long等数据写入Buffer该位置后,该位置将前进以指向缓冲区中的下一个要插入数据的单元。位置可以最大程度地变为 capacity - 1。

从a读取数据时,Buffer您也从指定位置读取数据。当您 Buffer从写入模式切换到读取模式时,该位置将重置为0。从中读取数据时,Buffer您将从中读取数据position,并position 前进到下一个读取位置。

2.3 限制

在写模式下,Buffer的限制是可以写入缓冲区的数据量的限制。在写入模式下,限制等于的容量Buffer。

当翻转Buffer到读模式,限制意味着多少数据可以从数据中读取的限制。因此,当将a切换Buffer到读取模式时,将限制设置为写入模式的写入位置。换句话说,您可以读取与写入的字节一样多的字节(限制设置为写入的字节数,该字节数由位置标记)。

3 Buffer的类型

Java NIO带有以下缓冲区类型:

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

如您所见,这些Buffer类型代表不同的数据类型。换句话说,它们使您可以将缓冲区中的字节作为char,short,int,long,float或double来使用。

4 Buffer的分配

要获取Buffer对象,您必须首先分配它。每个Buffer类都有一个allocate()执行此操作的方法。以下示例显示ByteBuffer了容量为48个字节的a的分配 :

ByteBuffer buf = ByteBuffer.allocate(48);

这是一个CharBuffer为1024个字符分配带空格的示例:

CharBuffer buf = CharBuffer.allocate(1024);

5 将数据写入Buffer

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

  1. 将数据从Channel写入Buffer
  2. Buffer通过缓冲区的put()方法将数据写入。

以下代码是Channel如何将数据写入Buffer的示例:

int bytesRead = inChannel.read(buf); //读入缓冲区。

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

buf.put(127);   

该put()方法还有许多其他版本,可让您以Buffer多种不同方式将数据写入 。例如,在特定位置写入或将字节数组写入缓冲区。有关更多详细信息,请参见JavaDoc以获取具体的缓冲区实现。

flip()方法

该flip()方法将Buffer从写入模式切换到读取模式。调用flip()会将positionback设置为0,并将设置为limit 刚才的位置。

换句话说,position现在标记读取位置,并limit标记将多少字节,字符等写入缓冲区-可以读取多少字节,字符等的限制。

6 从Buffer读取数据

您可以通过两种方式从读取数据Buffer。

  1. 从缓冲区读取数据到通道Channel。
  2. 使用get() 方法从缓冲区读取数据。

以下是如何从缓冲区将数据读取到通道的示例:

//从缓冲区读取到通道。
int bytesWritten = inChannel.write(buf);

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

byte aByte = buf.get();  

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

rewind()

该Buffer.rewind()套position回0,这样你就可以重新读取缓冲区中的所有数据。在limit保持不变,因此仍标记,可以从被读取许多元素(字节,字符等)如何Buffer。