Java Nio 的Buffer和優缺點

Java Nio 的Buffer

在數據傳輸的時候,我們會用到緩衝區。Java NIO中的Buffer用於和NIO通道進行交互。如你所知,數據是從通道讀入緩衝區,從緩衝區寫入到通道中的。緩衝區本質上是一塊可以寫入數據,然後可以從中讀取數據的內存。這塊內存被包裝成NIO Buffer對象,並提供了一組方法,用來方便的訪問該塊內存。Java的NIO 爲我們提供了原生的八種緩衝區實現,對應着Java 的七種基本類型和MappedByteBuffer。

Java NIO 有以下Buffer類型

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

Java中的這些Buffer已經足夠我們使用,但是這些確實基本的操作,在複雜的應用的時候就需要我們自己去封裝。由此我們可以知道netty爲什麼對java 的nio進行封裝了。

  1. 原生的Buffer,在創建緩存區的時候分指定分配的空間。一旦創建,就不能動態的擴展。
  2. 原生的Buffer中只有一個位置標記位,我們能修改通過操作這個標記爲來實現訪問和存取容易出錯。
  3. Buffer簡單功能的函數,需要我們自己實現複雜函數。

操作位置的函數

對緩衝區的讀寫操作首先要知道緩衝區的下限、上限和當前位置。下面這些變量的值對Buffer類中的某些操作有着至關重要的作用:

  1. limit:所有對Buffer讀寫操作都會以limit變量的值作爲上限。
  2. position:代表對緩衝區進行讀寫時,當前遊標的位置。
  3. capacity:代表緩衝區的最大容量(一般新建一個緩衝區的時候,limit的值和capacity的值默認是相等的)。

clear方法將緩衝區清空,一般是在重新寫緩衝區時調用。

public final Buffer clear() {
    position = 0; //重置當前讀寫位置
    limit = capacity; 
    mark = -1;  //取消標記
    return this;
}

反轉緩衝區。首先將限制設置爲當前位置,然後將位置設置爲 0。通常情況下,在準備從緩衝區中讀取數據時調用flip方法。

public final Buffer flip() {
     limit = position;
     position = 0;
     mark = -1;
     return this;
}

使緩衝區爲重新讀取已包含的數據做好準備:它使限制保持不變,將位置設置爲 0。

public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}

以上三種方法均使用final修飾,java.nio.Buffer的所有子類均使用同一種flip、clear和rewind機制。

這三個方法在源碼上就對緩衝區的數據不進行任何修改。

一旦讀完了所有的數據,就需要清空緩衝區,讓它可以再次被寫入。有兩種方式能清空緩衝區:調用clear()或compact()方法。clear()方法會清空整個緩衝區。compact()方法只會清除已經讀過的數據。任何未讀的數據都被移到緩衝區的起始處,新寫入的數據將放到緩衝區未讀數據的後面。

其他函數

  1. Buffer的分配

    每一個Buffer類都有一個allocate方法。ByteBuffer buf = ByteBuffer.allocate(48);

  2. 向Buffer中寫數據

    寫數據到Buffer有兩種方式:

    1. 從Channel寫到Buffer。int bytesRead = inChannel.read(buf); //read into buffer.
    2. 通過Buffer的put()方法寫到Buffer裏。buf.put(127);
  3. 從Buffer中讀取數據

    從Buffer中讀取數據有兩種方式:

    1. 從Buffer讀取數據到Channel。int bytesWritten = inChannel.write(buf);
    2. 使用get()方法從Buffer中讀取數據。byte aByte = buf.get();
  4. mark()與reset()方法

    通過調用Buffer.mark()方法,可以標記Buffer中的一個特定position。之後可以通過調用Buffer.reset()方法恢復到這個position。

  5. equals()與compareTo()方法

    可以使用equals()和compareTo()方法比較兩個Buffer。

  6. equals()

    當滿足下列條件時,表示兩個Buffer相等:

    1. 有相同的類型(byte、char、int等)。
    2. Buffer中剩餘的byte、char等的個數相等。
    3. Buffer中所有剩餘的byte、char等都相同。
      如你所見,equals只是比較Buffer的一部分,不是每一個在它裏面的元素都比較。實際上,它只比較Buffer中的剩餘元素。
  7. compareTo()方法

    compareTo()方法比較兩個Buffer的剩餘元素(byte、char等), 如果滿足下列條件,則認爲一個Buffer“小於”另一個Buffer:

    1. 第一個不相等的元素小於另一個Buffer中對應的元素 。
    2. 所有元素都相等,但第一個Buffer比另一個先耗盡(第一個Buffer的元素個數比另一個少)。

應用舉例

public static void main(String[] args) throws IOException {
    RandomAccessFile aFile = new RandomAccessFile("input/input.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
        }
        System.out.println("bytesRead = " + bytesRead);

        buf.clear();//make buffer ready for writing
        bytesRead = inChannel.read(buf);
    }
    aFile.close();
}

參考資料:
網上資料
備註:
轉載請註明出處:http://blog.csdn.net/wsyw126/article/details/75208264
作者:WSYW126

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