對於緩衝區來說,最重要的操作就是讀寫操作。緩衝區提供了兩種方法來讀寫緩衝區中的資料:get、put方法和array方法。而get、put方法可以有三種讀寫資料的方式:按順序讀寫單個資料、在指定位置讀寫單個資料和讀寫資料區塊。除了上述的幾種讀寫資料的方法外,CharBuffer類還提供了用於專門寫字串的put和append方法。在本文及後面的文章中將分別介紹這些讀寫緩衝區的方法。
雖然使用allocate方法建立的緩衝區並不是一次性地分配記憶體空間,但我們可以從使用者地角度將一個緩衝區想象成一個長度為capacity的數組。當緩衝區建立後,和數組一樣,緩衝區的大小(capacity值)將無法改變,也無法訪問緩衝區外的資料。如下面的代碼建立了一個大小為6的位元組緩衝區。
ByteBuffer byteBuffer = ByteBuffer.allocate(6);對於byteBuffer來說,只能訪問屬於這個緩衝區的六個位元組的資料,如果超過了這個範圍,將拋出一個BufferOverflowException異常,這是一個執行階段錯誤,因為這個錯誤只能在程式運行時被發現。
既然緩衝區和數組類似,那麼緩衝區也應該象數組一樣可以標識當前的位置。緩衝區的position方法為我們提供了這個功能。position方法有兩種重載形式,它們的定義如下:
public final int position()
public final Buffer position(int newPosition)
第一個重載形式用來擷取緩衝區的當前位置。在建立緩衝區後,position的初始值是0,也就是緩衝區第一個元素的位置。當從緩衝區讀取一個元素後,position的值加1。我們從這一點可以看出,position方法返回的位置就是當前可以讀取的元素的位置。position的取值範圍從0到capacity – 1。如果position的值等於capacity,說明緩衝區當前已經沒有資料可讀了。
position方法的第二個重載形式可以設定緩衝區的當前位置。參數newPosition的取值範圍是0 <= newPosition < capacity。如果newPosition的值超出這個範圍,position方法就會拋出一個IllegalArgumentException異常。
在大多數情況下不需要直接控制緩衝區的位置。緩衝區類提供的用於讀寫資料的方法可以自動地設定緩衝區的當前位置。在緩衝區類中,get和put方法用於讀寫緩衝區中的資料。get和put方法的定義如下:
ByteBuffer類的get和put方法:
public abstract byte get()
public abstract ByteBuffer put(byte b)
IntBuffer類的get和put方法:
public abstract int get()
public abstract IntBuffer put(int i)
其他五個緩衝區類中的get和put方法定義和上面的定義類似,只是get方法返回相應的資料類型,而put方法的參數是相應的資料類型,並且傳回值的類型是相應的緩衝區類。
每當put方法向緩衝區寫入一個資料後,緩衝區的當前位置都會加1。如果緩衝區的當前位置已經等於capacity,調用put方法就會拋出一個java.nio.BufferOverflowException異常。在緩衝區未初賦值的地區將被0填充。使用get方法可以得到緩衝區當前位置的資料,並使緩衝區的當前位置加1。和put方法一樣,在緩衝區當前位置等於capacity時使用get方法也會拋出java.nio.BufferOverflowException異常。緩衝區的初始狀態1所示。
圖1 緩衝區的初始狀態
從圖1可以看出,在緩衝區建立之初,當前的位置和緩衝區中的資料都為0。當使用如下語句向緩衝區中寫入資料後,緩衝區目前狀態2所示。
byteBuffer.put((byte)2);
byteBuffer.put((byte)-1);
圖2 緩衝區的目前狀態
當緩衝區的當前位置3所示時,使用put和get方法將會拋出上述的BufferOverflowException異常。
圖3 當前位置處於緩衝區尾
如果要使用get方法得到緩衝區中的指定資料,必須將緩衝區的當前位置移動到指定的位置,我們可以使用position方法將當前位置移到緩衝區的任何位置。如下面的代碼將圖3所示的緩衝區的當前位置設為2,並用get方法獲得位置2的資料:
byteBuffer.position(2);
System.out.println(byteBuffer.get());上面的代碼將輸出3。緩衝區的當前位置為除了使用position方法,也可以使用rewind方法將緩衝區的當前位置設為0,rewind方法的定義如下:
public final Buffer rewind()在圖2所示的緩衝區狀態下調用rewind方法,就會得到4的緩衝區狀態。
圖4 調用rewind方法後的緩衝區狀態
接下來讓我們執行如下語句:
System.out.println(byteBuffer.get());緩衝區的狀態將5所示。
圖5 調用get方法後的緩衝區狀態
緩衝區除了position和capacity外,還提供了一個標識來限制緩衝區可訪問的範圍。這個標識就是limit。limit和position一樣,在緩衝區類中也提供了兩個重載方法。用於獲得和設定limit的值。limit方法的定義如下:
public final int limit()
public final Buffer limit(int newLimit)
在初始狀態下,緩衝區的limit和capacity值相同。但limit和capacity的區別是limit可以通過limit方法進行設定,而capacity在建立緩衝區時就已經指定了,並且不能改變。(在上面所講的position方法的newPosition參數的取值範圍時曾說是0 <= newPosition < capacity,其實嚴格地說,應是0 <= newPosition < limit)limit的其他性質和capacity一樣。如在圖5所示的緩衝區狀態中將limit的值設為2,就變成了圖6所示的狀態。
圖6 將limit設為2的緩衝區狀態
在這時position的值等於limit,就不能訪問緩衝區的當前資料,也就是說不能使用get和put方法。否則將拋出BufferOverflowException異常。由於使用allocate建立的緩衝區並不是一次性地分配記憶體空間,因此,可以將緩衝區的capacity設為很大的值,如10M。緩衝區過大可能在某些環境中會使系統效能降低(如在PDA或智能插秧機中),因此,可以使用limit方法根據具體的情況來限定緩衝區的大小。當然,limit還可以表示緩衝區中實際的資料量,這將在後面講解。下面的代碼示範了如何使用limit方法來枚舉緩衝區中的資料:
while(byteBuffer.position() < byteBuffer.limit())
System.out.println(byteBuffer.get());我們還可以用flip和hasRemaining方法來重寫上面的代碼。flip方法將limit設為緩衝區的當前位置。當limit等於position時,hasRemaining方法返回false,而則返回true。 flip和hasRemaining方法的定義如下:
public final Buffer flip()
public final boolean hasRemaining()
下面的代碼示範了如何使用hasRemaining方法來枚舉緩衝區中的資料:
while(byteBuffer.hasRemaining())
System.out.println(byteBuffer.get());如果從緩衝區的第一個位置依次使用put方法向緩衝區寫資料,當寫完資料後,再使用flip方法。這樣limit的值就等於緩衝區中實際的資料量了。在網路中傳遞資料時,可以使用這種方法來設定資料的結束位置。
為了回顧上面所講內容,下面的代碼總結了建立緩衝區、讀寫緩衝區中的資料、設定緩衝區的limit和position的方法。
package net;
import java.nio.*;
public class GetPutData
{
public static void main(String[] args)
{
// 建立緩衝區的四種方式
IntBuffer intBuffer = IntBuffer.allocate(10);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);
CharBuffer charBuffer = CharBuffer.wrap("abcdefg");
DoubleBuffer doubleBuffer = DoubleBuffer.wrap(new double[] { 1.1, 2.2 });
// 向緩衝區中寫入資料
intBuffer.put(1000);
intBuffer.put(2000);
System.out.println("intBuffer的當前位置:" + intBuffer.position());
intBuffer.position(1); // 將緩衝區的當前位置設為1
System.out.println(intBuffer.get()); // 輸出緩衝區的當前資料
intBuffer.rewind(); // 將緩衝區的當前位置設為0
System.out.println(intBuffer.get()); // 輸出緩衝區的當前資料
byteBuffer.put((byte)20);
byteBuffer.put((byte)33);
byteBuffer.flip(); // 將limit設為position,在這裡是2
byteBuffer.rewind();
while(byteBuffer.hasRemaining()) // 枚舉byteBuffer中的資料
System.out.print(byteBuffer.get() + " ");
while(charBuffer.hasRemaining()) // 枚舉charBuffer中的資料
System.out.print(charBuffer.get() + " ");
// 枚舉doubleBuffer中的資料
while(doubleBuffer.position() < doubleBuffer.limit())
System.out.print(doubleBuffer.get() + " ");
}
}
運行結果:
intBuffer的當前位置:2
2000
1000
20 33 a b c d e f g 1.1 2.2
注意:如果必須使用緩衝區的大小來讀取緩衝區的資料,盡量不要使用capacity,而要使用limit。如盡量不要寫成如下的代碼:
while(byteBuffer.position() < byteBuffer.capacity())
System.out.println(byteBuffer.get());這是因為當limit比capacity小時,上面的代碼將會拋出一個BufferUnderflowException異常。
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/nokiaguy/archive/2009/10/09/4682908.aspx