1. 程式人生 > 其它 >Java NIO ByteBuffer 的 position,limit,capacity 和

Java NIO ByteBuffer 的 position,limit,capacity 和

狀態變數

在緩衝區中,最重要的狀態變數有下面三個,它們一起合作完成對緩衝區內部狀態的變化跟蹤:
position:指定了下一個將要被寫入或者讀取的元素索引,它的值由get()/put()方法自動更新,在新建立一個Buffer物件時,position被初始化為0。您可以回想一下,緩衝區實際上就是美化了的陣列。在從通道讀取時,您將所讀取的資料放到底層的陣列中。 position 變數跟蹤已經寫了多少資料。更準確地說,它指定了下一個位元組將放到陣列的哪一個元素中。因此,如果您從通道中讀三個位元組到緩衝區中,那麼緩衝區的 position將會設定為3,指向陣列中第四個元素。同樣,在寫入通道時,您是從緩衝區中獲取資料。 position 值跟蹤從緩衝區中獲取了多少資料。更準確地說,它指定下一個位元組來自陣列的哪一個元素。因此如果從緩衝區寫了5個位元組到通道中,那麼緩衝區的 position 將被設定為5,指向陣列的第六個元素。position 總是小於或者等於 limit。
limit:

指定還有多少資料需要取出(在從緩衝區寫入通道時),或者還有多少空間可以放入資料(在從通道讀入緩衝區時)。
capacity:指定了可以儲存在緩衝區中的最大資料容量,實際上,它指定了底層陣列的大小,或者至少是指定了准許我們使用的底層陣列的容量。

以上三個屬性值之間有一些相對大小的關係:0 <= position <= limit <= capacity。如果我們建立一個新的容量大小為10的ByteBuffer物件,在初始化的時候,position設定為0,limit和 capacity被設定為10,在以後使用ByteBuffer物件過程中,capacity的值不會再發生變化,而其它兩個個將會隨著使用而變化。三個屬性值分別如圖所示:

現在我們可以從通道中讀取一些資料到緩衝區中,注意從通道讀取資料,相當於往緩衝區中寫入資料。如果讀取4個自己的資料,則此時position的值為4,即下一個將要被寫入的位元組索引為4,而limit仍然是10

下一步把讀取的資料寫入到輸出通道中,相當於從緩衝區中讀取資料,在此之前,必須呼叫flip()方法,該方法將會完成兩件事情:
1. 把limit設定為當前的position值
2. 把position設定為0
由於position被設定為0,所以可以保證在下一步輸出時讀取到的是緩衝區中的第一個位元組,而limit被設定為當前的position,可以保證讀取的資料正好是之前寫入到緩衝區中的資料

在從緩衝區中讀取資料完畢後,limit的值仍然保持在我們呼叫flip()方法時的值,呼叫clear()方法能

夠把所有的狀態變化設定為初始化時的值,如下圖所示:

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

 
public class Program {

public static void main(String args[]) throws Exception {
FileInputStream fin = new FileInputStream("d:\\test.txt");
FileChannel fc = fin.getChannel();

 
ByteBuffer buffer = ByteBuffer.allocate(10);
output("初始化", buffer);
 
fc.read(buffer);
output("呼叫read()", buffer);

 
buffer.flip();
output("呼叫flip()", buffer);
while (buffer.remaining() > 0) {
byte b = buffer.get();
// System.out.print(((char)b));
}

output("呼叫get()", buffer);
buffer.clear();
output("呼叫clear()", buffer);
fin.close();
}

 
public static void output(String step, Buffer buffer) {
System.out.println(step + " : ");
System.out.print("capacity: " + buffer.capacity() + ", ");
System.out.print("position: " + buffer.position() + ", ");
System.out.println("limit: " + buffer.limit());
System.out.println();
}

}

訪問方法

get() 方法,ByteBuffer 類中有四個 get() 方法:
1. byte get(); 第一個方法獲取單個位元組
2. ByteBuffer get( byte dst[] );第二和第三個方法將一組位元組讀到一個數組中
3. ByteBuffer get( byte dst[], int offset, int length );第二和第三個方法將一組位元組讀到一個數組中
4. byte get( int index );第四個方法從緩衝區中的特定位置獲取位元組

我們認為前三個 get() 方法是相對的,而最後一個方法是絕對的。 相對意味著 get() 操作服從 limit 和 position 值 ― 更明確地說,
位元組是從當前 position 讀取的,而 position 在 get 之後會增加。另一方面,一個 絕對方法會忽略 limit 和 position 值,也不會影響它們.
事實上,它完全繞過了緩衝區的統計方法。上面列出的方法對應於 ByteBuffer 類。其他類有等價的 get() 方法,這些方法除了不是處理位元組外,
其它方面是是完全一樣的,它們處理的是與該緩衝區類相適應的型別。

put()方法,ByteBuffer 類中有五個 put() 方法:
1. ByteBuffer put( byte b );第一個方法 寫入(put) 單個位元組
2. ByteBuffer put( byte src[] );第二和第三個方法寫入來自一個數組的一組位元組。
3. ByteBuffer put( byte src[], int offset, int length );
4. ByteBuffer put( ByteBuffer src );第四個方法將資料從一個給定的源ByteBuffer 寫入這個ByteBuffer。
5. ByteBuffer put( int index, byte b );第五個方法將位元組寫入緩衝區中特定的 位置 。

與 get() 方法一樣,我們將把 put() 方法劃分為 相對 或者 絕對 的。前四個方法是相對的,
而第五個方法是絕對的。上面顯示的方法對應於 ByteBuffer 類。其他類有等價的 put() 方法,
這些方法除了不是處理位元組之外,其它方面是完全一樣的。它們處理的是與該緩衝區類相適應的型別。

型別化的 get() 和 put() 方法:
除了前些小節中描述的 get() 和 put() 方法, ByteBuffer 還有用於讀寫不同型別的值的其他方法,如下所示,
getByte()、getChar()、getShort()、getInt()、getLong()、getFloat()、getDouble()、putByte()、putChar()、 putShort()、putInt()、putLong()、putFloat()、putDoubl