天天看點

java nio之Buffer(一)

buffer是一個包裝了基本資料元素數組的對象,它以及它的子類定義了一系列api用于處理資料緩存。

java nio之Buffer(一)

一、屬性

buffer有四個基本屬性:

1、capacity  容量,buffer能夠容納的最大元素數目,在buffer建立時設定并不能更改

2、limit buffer中有效位置數目

3、position 下一個讀或者寫的位置

4、mark  用于記憶的标志位,配合reset()使用,初始值未設定,調用mark後将目前position設為值

四者關系:0 <= mark <= position <= limit <= capacity

二、api

package java.nio;

public abstract class buffer {

public final int capacity( )

public final int position( )

public final buffer position (int newposition)

public final int limit( )

public final buffer limit (int newlimit)

public final buffer mark( )

public final buffer reset( )

public final buffer clear( )

public final buffer flip( )

public final buffer rewind( )

public final int remaining( )

public final boolean hasremaining( )

public abstract boolean isreadonly( );

}

支援鍊式調用,如:buffer.mark().position(5).reset( );

注意isreadonly()方法決定了buffer是否可寫。

三、操作

  以bytebuffer為例,

1、通路,通過get(),get(index),其中get()從目前position位置讀取,get(index)從index位置讀取,不改變目前position,下面要說到的put也一樣。

2、填充,通過put(byte),put(index,byte),按照絕對位置填充也是不改變目前position屬性

3、flipping,試想,我們将填充完畢的buffer傳遞給socket輸出,那麼socket讀取是依據position屬性确定,就會從結尾後一位開始讀,這樣肯定是不正确的,如果要正确的讀取我們先要:

  buffer.limit(buffer.position( )).position(0);

将limit設為position, 将position設為0,這個操作就叫flipping,api直接提供了這個操作:

  buffer.flip( );

特别注意,flip()方法會改變limit屬性,将limit屬性從capacity設定為目前position。rewind()方法與flip()類似,但是僅将position設為0,而不改變limit,通常用于重新讀取已經被flip的buffer。flip()另一個注意點是,兩次調用buffer的flip方法,将使得position和limit屬性都為0。

4、疊代取元素:

for (int i = 0; buffer.hasremaining( ), i++) {

mybytearray [i] = buffer.get( );

int count = buffer.remaining( );

for (int i = 0; i < count, i++) {

bytebuffer不是線程安全的,前一種方式适合并發通路,後一種方式效率更高。這兩種方式都是一個一個取,效率都比批量取低。

5.clear()方法,将buffer重設為空狀态,也就是設定limit=capacity,position=0,以便重複利用。

6.compact()方法,用于壓縮buffer,這個方法在多次重複調用時是比較低效。

7.mark(),初始是未定義的,這适合如果調用reset将抛出invalidmarkexception。調用makr()後,将目前position設為mark以便reset時傳回。注意,rewind( ), clear( ), and flip( )方法都将丢棄已經建立的mark。調用limit(index),positioon(index),如果index的值小于目前mark,mark也将被丢棄。

8.比較,可以通過equals()和compateto()方法來比較兩個buffer,前一個傳回boolean,後一個傳回0,-1,1。兩個buffer equal的條件是:

1)類型相同

2)剩餘元素的數目相等

3)剩餘元素也一一相等

9、批量移動資料,為了更有效地進行資料傳送,批量的資料存取肯定是不能少的,buffer及其子類都有提供類似的方法,比如charbuffer:

public charbuffer get (char [] dst)

public charbuffer get (char [] dst, int offset, int length)

public final charbuffer put (char[] src)

public charbuffer put (char [] src, int offset, int length)

public charbuffer put (charbuffer src)

public final charbuffer put (string src)

public charbuffer put (string src, int start, int end)

四、建立buffer

    buffer以及其子類都無法直接new,而必須把通過他們提供的工廠方法來建立。通常有兩種方式:

1、allocate,例如

charbuffer charbuffer = charbuffer.allocate (100);

将在堆上配置設定一個可以存儲100個字元的數組作為backing store。

2、wrap,包裝一個已有的數組:

char [] myarray = new char [100];

charbuffer charbuffer = charbuffer.wrap (myarray);

注意,這樣的方式建立的buffer,将不會在堆上建立新的數組,而是直接利用myarray做backing store,這意味着任何對myarray或者buffer的修改都将影響到buffer或者myarray。可以通過public final boolean hasarray( )方法來判斷是否擁有一個數組,通過array()方法取得這個數組。

五、複制buffer

   其實這個複制也是“淺拷貝”,通過duplicate()方法将傳回一個新建立的buffer,這個新buffer與原來的buffer共享資料,一樣的capacity,但是有自己的position、limit和mark屬性。通過asreadonlybuffer()方法複制的buffer與duplicate()類似,但是是隻讀的,不能調用put。比較特别的是slice()方法,故名思議,類似切割一個buffer出來,與duplicate類似,但是它将從原來buffer的目前position開始,并且capacity等于原來buffer的剩餘元素數目,也就是(limit-position)。

文章轉自莊周夢蝶  ,原文釋出時間2008-02-22