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、所有元素都是相等的,但是第一個緩衝區在第二個緩衝區之前用完了元素(它的元素更少)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章