NIO 筆記二 緩衝區

2021-10-08 15:53:01 字數 3805 閱讀 7565

乙個 buffer 物件是固定數量的資料的容器。其作用是乙個儲存器,或者分段運輸區,在這裡資料可被儲存並在之後用於檢索。對於每個非布林原始資料型別都有乙個緩衝區類。儘管緩衝區作用於它們儲存的原始資料型別,但緩衝區十分傾向於處理位元組。非位元組緩衝區可以在後台執行從位元組或到位元組的轉換,這取決於緩衝區是如何建立的(這暗含了按位元組排序的問題)。

緩衝區的工作與通道緊密聯絡。通道是 i/o 傳輸發生時的入口,而緩衝區是這些資料傳輸的**或目標。對於離開緩衝區的傳輸,你想要傳遞出去的資料被置於乙個緩衝區,被傳送到通道。對於傳回緩衝區的傳輸,乙個通道將資料放置在你鎖提供的緩衝中。這種在協同物件(通常是你所寫的物件以及一到多個 channel 物件)之間進行的緩衝區資料傳遞是高效資料處理的關鍵。

緩衝區基礎:概念上,緩衝區是包在乙個物件內的基本資料元素陣列。buffer 類相比乙個簡單陣列的優點是它將關於資料的資料內容和資訊包含在乙個單一的物件中

屬性名描述

容量(capacity)

緩衝區能夠容納的資料元素的最大數量。這一容量在緩衝區建立時被設定,並且永遠不能被改變

上界(limit)

緩衝區第乙個不能被讀或寫的元素。或者說,緩衝區中現存元素的計數

位置(position)

下乙個要被讀或寫的元素的索引。位置會自動由相應的get() 和 put() 函式更新

標記(mark)

乙個備忘位置。呼叫 mark() 來設定 mark = position。呼叫 reset() 設定 position = mark.標記在設定前是未定義的(undifined)

這四個屬性之間總是遵循以下關係:

0 <= mark <= position <= limit <= capacity

有一點要說明的是,像 clear() 這類方法,您通常應當返回 void, 而不是 buffer 引用。這些函式將引用返回到它們在(this)上被引用的物件。這時乙個允許級聯呼叫的類設計方法,如:

// 如果使用級聯呼叫會使**作用不夠清晰,那麼請不要使用它。請時刻保證您的**易於他人閱讀

buffer.

mark()

.position(5

).reset()

;

一、翻轉

@test

public

void

testflip()

throws exception

問: 如果將緩衝區翻轉兩次(指連續翻轉兩次)會怎麼樣呢?

答: 它實際上會大小變為 0.它會把上界(limit)設為位置(position)的值,並把位置(position)設定為 0.嘗試對緩衝區上位置(position)和上界(limit)都為0的get()操作會導致 bufferunderflowexception 異常,而 put() 則會導致 bufferoverflowexception 異常

二、釋放

如果你接收到乙個在別處被填滿的緩衝區,你可能需要在檢索內容之前將其翻轉。例如:如果乙個通道的 read() 操作完成,而你想要檢視被通道放入緩衝區內的資料,那麼你需要在呼叫 get() 之前翻轉緩衝區。通道物件在緩衝區上呼叫 put()增加資料;put 和 read 可以隨意混合使用

布林方法 hasremaining() 會在釋放緩衝區時告訴你是否已經達到緩衝區的上界。

remaining() 方法將告知你從當前位置到上界還剩餘的元素數目(可用於對緩衝區的控制)

clear() 方法將緩衝區重置為空狀態,它並不改變緩衝區的任何資料元素,而僅僅將上界設定為容量的值,並把位置設回 0

注意: 緩衝區並不是執行緒安全的。如果你想要以多執行緒同時訪問特定的緩衝區,需要在訪問緩衝區之前進行同步(例如對緩衝區物件進行跟蹤)

@test

public

void

testrelease()

throws exception

}

執行效果:

三、壓縮

有時,你可能只想從緩衝區中釋放一部分資料,而不是全部,然後重新填充。為了實現這一點,未讀的元素需要下移以使第乙個元素索引為 0.儘管重複這樣做效率低下,但這有時非常必要,而 api 對此提供了乙個 compact() 方法。這一緩衝區工具在複製資料時要比你使用 get() 和 put() 方法高效得多,所以,當你需要時,請使用 compact();說白了就是將 position 與 limit 之間的資料複製到 buffer 的開始位置,複製後 position = limit -position,limit = capacity,但如果 position 與 limit 之間沒有資料的話,就不會進行複製,看案例吧!

@test

public

void

testcompact()

throws exception

1.buffer中新增 「hello」 後 此時position 為 5 limit 為 10

buffer 執行 flip 後,此時position 為 0 limit 為 5

buffer 執行 put乙個 'm』後,此時position 為 1 limit 為 5

四、比較

有時候比較兩個緩衝區所包含的資料是很有必要的。所有的緩衝區都提供了乙個常規的equals() 方法用以測試兩個緩衝區是否相等,以及乙個compareto() 方法用以比較緩衝區:

// 兩個緩衝區可用下面的**來測試是否相等: 

if(buffer1.equals (buffer2)

)

每個緩衝區中剩餘的內容相同,那麼 equals() 函式將返回 true,否則返回 false.因為這個測試時用於嚴格的相等而且是可換向的,前面的程式清單中的緩衝區名稱可以顛倒,並會產生相同的結果。

兩個緩衝區被認為相等的充要條件是:

① 兩個物件型別相同。包含不同資料型別的 buffer 永遠不會相等,而且 buffer 絕不會等於非 buffer 物件

② 兩個物件都剩餘同樣數量的元素。buffer 的容量不需要相同,而且緩衝區中剩餘資料的索引也不必相同。但每個緩衝區剩餘元素的數目(從位置到上界)必須相同

③ 在每個緩衝區中應被 get() 方法返回的剩餘資料元素序列必須一致

如果不滿足以上任意條件,就會返回 false

compareto() 不允許不同物件進行比較,如過你傳遞乙個型別錯誤的物件,它會丟擲 classcastexception 異常

五、批量移動

緩衝區的設計目的是為了能夠高效傳輸資料,buffer api 提供了向緩衝區內批量移動資料元素的函式。有兩種形式的 get() 可供從緩衝區到陣列進行資料複製使用。第一種形式只將乙個陣列作為引數,將乙個緩衝區釋放到給定的陣列,第二種形式使用 offset 和 length 引數來指定目標陣列的子區間,批量移動的效果比迴圈可能高效得多,因為這種緩衝區實現能夠利用本地**或其它的優化來移動資料。

批量移動總是具有指定的長度。

注意: 批量傳輸的大小總是固定的,省略長度意味著整個陣列會被填滿

如果你所要求的數量資料不能被傳送,那麼不會有資料被傳遞,緩衝區的狀態保持不變,同時丟擲 bufferunderflowexception 異常。因此當您傳入乙個陣列並且沒有指定長度,您就相當於要求整個陣列被填充。如果緩衝區的資料不夠完全填滿陣列,你會得到乙個異常,這意味著你想將乙個小型緩衝區傳入乙個大型陣列,你需要明確的指定緩衝區剩餘的資料長度

nio學習01 緩衝區

緩衝區是包在乙個物件內的基本資料元素陣列。buffer類似相比乙個簡單的陣列優點是它將關於資料的資料內容和資訊包含在乙個單一的物件中。buffer類似及它專有的子類定義了乙個用於處理緩衝區的api。他的本質是一塊可以寫入資料,然後可以從中讀取資料的記憶體。這塊記憶體被包裝成nio物件,並提供了一組方...

IO模型 NIO緩衝區

緩衝區 buffer 緩衝區本質上是一塊可以寫入資料,然後可以從中讀取資料的記憶體 底層是陣列 這塊記憶體被包裝成nio buffer物件,並提供了一組方法,用來方便的訪問該塊記憶體。理解buffer的工作原理,需要熟悉它的三個屬性 capacity 容量,即可以容納的最大資料量 在緩衝區建立時被設...

NIO學習筆記之緩衝區Buffer

buffer有四個屬性 1 capacit 容量 2 limit 上界 3 position 位置 4 mark 標記 絕對儲存不會影響緩衝區的位置屬性 存和取的方法 public abstract byte get public abstract byte get int index public...