略解ByteBuf

說到ByteBuf,咱們並不陌生,官網給的解釋爲,一個能夠進行隨機訪問或者是順序訪問的字節集合,它是NIO buffers緩衝的底層抽象。既然是底層抽象,那麼咱們就能夠基於其衍生出不少的具體實現出來,事實上,netty中的不少緩衝組件都是基於此抽象類作的擴展。html

隨機訪問索引api

和普通的字節數據同樣,ByteBuf也是從0開始索引的。這就意味着第一個字節的索引永遠是0,而最後一個字節的索引則是capacity。舉個例子,當咱們去遍歷緩衝中的全部字節的時候,咱們能夠按照以下方式來作:數組

 ByteBuf buffer = ...;
 for (int i = 0; i < buffer.capacity(); i ++) {
     byte b = buffer.getByte(i);
     System.out.println((char) b);
 }

能夠清楚的看到,其使用方式和遍歷字節數組同樣的作法。咱們能夠隨機的獲取緩衝區裏面的任意一個字節。緩存

順序訪問索引less

這個ByteBuf的實現中,有三個比較有意思的屬性,readerIndex,writerIndex,capacity,從字面意思上,咱們能夠理解爲讀索引,寫索引,容量。下圖則展現了三個屬性之間的關係:dom

image

首先是readable bytes(可讀字節數組),裏面放置的是真實的數據,當使用帶有read或者是skip的方法來操做此數據內容的時候,都將致使readerIndex遞增。若是當前內容讀取完畢,沒有更多的內容能夠讀取,那麼嘗試讀取將會拋出IndexOutOfBoundsException。默認狀況下,一個新分配的緩衝區或者包裝的緩衝區或者複製的緩衝區,其readerIndex的初始值爲0。示例讀取代碼以下:spa

// Iterates the readable bytes of a buffer.
 ByteBuf buffer = ...;
 while (buffer.isReadable()) {
     System.out.println(buffer.readByte());
 }

其次是writable bytes(可寫字節數組),裏面是空數據,待被真實數據覆蓋。當使用帶有write的方法來操做此數據內容的時候,都將致使writerIndex遞增。若是當前已無足夠的空間可寫,那麼嘗試寫入將會拋出IndexOutOfBoundsException。默認狀況下,一個新分配的緩存區,其writerIndex的初始值爲0。包裝的緩衝區或者複製的緩衝區,其writerIndex等於capacity。示例寫入代碼以下:.net

 // Fills the writable bytes of a buffer with random integers.
 ByteBuf buffer = ...;
 while (buffer.maxWritableBytes() >= 4) {
     buffer.writeInt(random.nextInt());
 }
 

最後是discardable bytes(廢棄字節數組),此數組裏面是已經讀取過的數據。開始的時候,其值默認爲0,可是當進行讀取操做的時候,它的值開始慢慢遞增,直至和writerIndex相等。這些字節能夠經過調用discardReadBytes()方法來進行釋放,釋放前和釋放後的圖示示例以下:netty

釋放前:code

image

釋放後:

image

須要注意的是,不一樣緩衝區的底層實現,可能會讓writable bytes裏面填充進徹底不一樣的數據,因此使用此方法的時候,還請審慎。

你能夠調用clear()方法來重置readerIndex和writerIndex爲0。此方法不會清理掉真實的數據,而是僅僅重置這兩個索引。

清理前:

image

清理後:

image

須要注意的是,此種狀況下可能會覆蓋原有緩衝數據,使用的事情請謹慎。

搜索操做

簡單的單個字節搜索,可使用indexOf(int, int, byte)bytesBefore(int, int, byte)來實現。bytesBefore(byte) 適用於簡單的String搜索。  forEachByte(int, int, ByteBufProcessor) 適用於比較複雜的搜索。

建立緩衝副本

你可使用duplicate(), slice() 或者 slice(int, int)來建立已有緩衝的衍生副本。衍生的緩衝副本將會有獨立的readerIndex,writerIndex和標記索引,可是如同其餘NIO 緩衝區同樣,他會共享內部的數據。爲了可以得到一份真正的全新的緩衝拷貝,可使用copy()方法來進行。須要注意的是,衍生的緩衝將不會調用retain()方法,由於其reference count將不會增長。

JDK類型轉換

你可使用array()方法來使ByteBuf支持字節數組(好比 byte[])。同時也可使用hasArray()方法來檢測其是否支持字節數組。

你可使用nioBuffer()方法來使ByteBuf支持NIO ByteBuffer。同時也可使用nioBufferCount()方法來檢測其是否可以被轉換爲NIO buffer。

你可使用toString(Charset)方法來使ByteBuf轉換成String。須要注意的是,toString()方法並不是類型轉換的方法。

你可使用ByteBufInputStream和ByteBufOutputStream來進行IO流的轉換。

相關文章
相關標籤/搜索