Java NIO Buffer

源自:http://tutorials.jenkov.com/java-nio/buffers.html

Java NIO Buffers are used when interacting with NIO Channels. As you know, data is read from channels into buffers, and written from buffers into channels.

Java Nio 缓冲器用于Nio 通道的交互。如你所知,数据从通道读取到缓冲区,然后从缓冲区写入通道。

A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block.

缓冲区实质上是一个内存块,您可以将数据写入其中,然后可以再次读取。这个内存块被包装在一个NIO缓冲区对象中,该对象提供了一组方法,使处理内存块更加容易。

Basic Buffer Usage

Using a Buffer to read and write data typically follows this little 4-step process:

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

  1. Write data into the Buffer 将数据写入缓冲区
  2. Call buffer.flip() 调用buffer.flip()方法
  3. Read data out of the Buffer  从缓冲区中读取数据
  4. Call buffer.clear() or buffer.compact() 调用buffer.clear() 或者buffer.compact()

When you write data into a buffer, the buffer keeps track of how much data you have written. Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip() method call. In reading mode the buffer lets you read all the data written into the buffer.

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

Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data.

一旦读取了所有的数据,就需要清除缓冲区,使其可以再次写入。您可以通过两种方式来实现这一点:调用clear()或调用compact()。clear()方法清除整个缓冲区。compact()方法只清除已读取的数据。任何未读数据都将移动到缓冲区的开头,数据将在写入未读数据之后的缓冲区。

Here is a simple Buffer usage example, with the write, flip, read and clear operations maked in bold:

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

A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block.

缓冲区实质上是一个内存块,您可以将数据写入其中,然后可以再次读取。这个内存块包装在一个NIO缓冲区对象中,该对象提供了一组方法,使处理内存块更加容易。

Buffer has three properties you need to be familiar with, in order to understand how a Bufferworks. These are:

  • capacity
  • position
  • limit

缓冲区有三个你需要熟悉的属性,以便了解缓冲区是如何工作的。它们是capacity,position,limit

The meaning of position and limit depends on whether the Buffer is in read or write mode. Capacity always means the same, no matter the buffer mode.

position和limit的含义取决于缓冲区是处于读还是写模式。容量总是意味着相同的,不管是缓冲模式。

Here is an illustration of capacity, position and limit in write and read modes. The explanation follows in the sections after the illustration.

这是写和读模式下的容量、位置和限制的图示。说明如下所示。

Capacity

Being a memory block, a Buffer has a certain fixed size, also called its "capacity". You can only write capacity bytes, longs, chars etc. into the Buffer. Once the Buffer is full, you need to empty it (read the data, or clear it) before you can write more data into it.

作为内存块,缓冲区有一定的固定大小,也称为“容量”。您只能将字节、长整型、字符等写入缓冲区。一旦缓冲区满了,您需要清空它(读取数据或清除数据),然后才能向其中写入更多数据。

Position

When you write data into the Buffer, you do so at a certain position. Initially the position is 0. When a byte, long etc. has been written into the Buffer the position is advanced to point to the next cell in the buffer to insert data into. Position can maximally become capacity - 1.

当你将数据写入缓冲区时,你会在某个位置执行此操作。最初位置为0。当一个byte、long等被写入缓冲区时,该位置将被前进,指向缓冲区中要插入数据的下一个单元格。位置最大可变成(容量-1)。

When you read data from a Buffer you also do so from a given position. When you flip a Bufferfrom writing mode to reading mode, the position is reset back to 0. As you read data from the Buffer you do so from position, and position is advanced to next position to read.

当你从缓冲区读取数据时,也会从给定位置读取数据。当你将缓冲区从写入模式切换到读取模式时,位置将重置回0。当你从缓冲区的position读取数据时,位置被提升到下一个要读取的位置。

Limit

In write mode the limit of a Buffer is the limit of how much data you can write into the buffer. In write mode the limit is equal to the capacity of the Buffer.

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

When flipping the Buffer into read mode, limit means the limit of how much data you can read from the data. Therefore, when flipping a Buffer into read mode, limit is set to write position of the write mode. In other words, you can read as many bytes as were written (limit is set to the number of bytes written, which is marked by position).

将缓冲区翻转为读取模式时,限制意味着可以从数据中读取的数据量的限制。因此,当将缓冲区翻转到读取模式时,将limit设置为写入模式的写入位置。换句话说,你可以读取写入的字节数(limit设置为写入的字节数,由位置标记)。

Buffer Types

Java NIO comes with the following Buffer types:

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

As you can see, these Buffer types represent different data types. In other words, they let you work with the bytes in the buffer as char, short, int, long, float or double instead.

如你所见,这些缓冲区类型表示不同的数据类型。换句话说,它们允许你将缓冲区中的字节改为char、short、int、long、float或double。

The MappedByteBuffer is a bit special, and will be covered in its own text.

MappedByteBuffer 有点特别,将在自己的文本中介绍。

Allocating a Buffer

To obtain a Buffer object you must first allocate it. Every Buffer class has an allocate() method that does this. Here is an example showing the allocation of a ByteBuffer, with a capacity of 48 bytes:

要获得缓冲区对象,必须首先分配它。每个buffer类都有一个allocate()方法来执行此操作。下面是一个例子,显示了一个字节缓冲区的分配,其容量为48字节:

ByteBuffer buf = ByteBuffer.allocate(48);

Here is an example allocating a CharBuffer with space for 1024 characters:

CharBuffer buf = CharBuffer.allocate(1024);

Writing Data to a Buffer

You can write data into a Buffer in two ways:

  1. Write data from a Channel into a Buffer
  2. Write data into the Buffer yourself, via the buffer's put() methods.

您可以通过两种方式将数据写入缓冲区:

1、将通道的数据写入缓冲区

2、通过缓冲区的put()方法,自己将数据写入缓冲区。

Here is an example showing how a Channel can write data into a Buffer:

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

Here is an example that writes data into a Buffer via the put() method:

buf.put(127);

There are many other versions of the put() method, allowing you to write data into the Buffer in many different ways. For instance, writing at specific positions, or writing an array of bytes into the buffer. See the JavaDoc for the concrete buffer implementation for more details.

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

flip()

The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was.

flip()方法将缓冲区从写入模式切换到读取模式。调用flip()将位置设置为0,并将limit设置为位置刚刚所在的位置。

In other words, position now marks the reading position, and limit marks how many bytes, chars etc. were written into the buffer - the limit of how many bytes, chars etc. that can be read.

换句话说,position现在标记读取位置,limit标记写入缓冲区的字节数、字符数等.(可以读取的字节、字符等的限制。)

Reading Data from a Buffer

There are two ways you can read data from a Buffer.

  1. Read data from the buffer into a channel.
  2. Read data from the buffer yourself, using one of the get() methods.

有两种方法可以从缓冲区读取数据:

1、将从缓冲区读数据,并写入通道中。

2、使用get()方法之一,自己从缓冲区读取数据。

Here is an example of how you can read data from a buffer into a channel:

//read from buffer into channel.
int bytesWritten = inChannel.write(buf);

Here is an example that reads data from a Buffer using the get() method:

byte aByte = buf.get();  

There are many other versions of the get() method, allowing you to read data from the Buffer in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details.

有许多其他版本的get()方法,允许你以许多不同的方式从缓冲区读取数据。例如,在特定位置读取,或者从缓冲区读取字节数组。有关具体缓冲区实现的更多详细信息,请参阅JavaDoc。

rewind()

The Buffer.rewind() sets the position back to 0, so you can reread all the data in the buffer. The limit remains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the Buffer.

buffer.rewind()将位置设置回0,以便可以重新读取缓冲区中的所有数据。limit保持不变,因此仍然标记可以从缓冲区读取的元素数(字节、字符等)。

clear() and compact()

Once you are done reading data out of the Buffer you have to make the Buffer ready for writing again. You can do so either by calling clear() or by calling compact().

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

If you call clear() the position is set back to 0 and the limit to capacity. In other words, the Buffer is cleared. The data in the Buffer is not cleared. Only the markers telling where you can write data into the Buffer are.

如果你调用clear(),则position设置为0,并且limit设置为capacity。换句话说,缓冲区被清除。缓冲区中的数据未清除。只有标记告诉你可以在哪里将数据写入缓冲区。

If there is any unread data in the Buffer when you call clear() that data will be "forgotten", meaning you no longer have any markers telling what data has been read, and what has not been read.

如果在调用clear()时缓冲区中有任何未读数据,该数据将被“遗忘”,也就是说,你不再有任何标记来指示哪些数据已被读取,哪些数据未被读取。

If there is still unread data in the Buffer, and you want to read it later, but you need to do some writing first, call compact() instead of clear().

如果缓冲区中仍有未读数据,你希望稍后再读取它,但需要先进行一些写入,请调用compact()而不是clear()。

compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element. The limit property is still set to capacity, just like clear() does. Now the Buffer is ready for writing, but you will not overwrite the unread data.

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

mark() and reset()

You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method. Here is an example:

通过调用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.  

equals() and compareTo()

It is possible to compare two buffers using equals() and compareTo().

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

equals()

Two buffers are equal if:

  1. They are of the same type (byte, char, int etc.)
  2. They have the same amount of remaining bytes, chars etc. in the buffer.
  3. All remaining bytes, chars etc. are equal.

两个缓冲区相等,需要满足如下条件:

1、它们的类型相同(byte、char、int等)。

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

3、所有剩余的字节、字符等都相等。

As you can see, equals only compares part of the Buffer, not every single element inside it. In fact, it just compares the remaining elements in the Buffer.

如你所见,equals只比较缓冲区的一部分,而不是缓冲区内的每个元素。实际上,它只是比较缓冲区中的其余元素。

compareTo()

The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if:

  1. The first element which is equal to the corresponding element in the other buffer, is smaller than that in the other buffer.
  2. All elements are equal, but the first buffer runs out of elements before the second buffer does (it has fewer elements).

compareto()方法比较两个缓冲区的剩余元素(字节、字符等),以便在排序例程中使用。

如果出现以下情况,则认为缓冲区比另一个缓冲区“小”:

1、第一个元素等于另一个缓冲区中的对应元素,它小于另一个缓冲区中的对应元素。

2、所有元素都是相等的,但是第一个缓冲区在第二个缓冲区之前用完了元素(它的元素更少)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值