略解ByteBuf
說到ByteBuf,我們並不陌生,官網給的解釋為,一個可以進行隨機訪問或者是順序訪問的字節集合,它是NIO buffers緩沖的底層抽象。既然是底層抽象,那麽我們就可以基於其衍生出很多的具體實現出來,事實上,netty中的很多緩沖組件都是基於此抽象類做的擴展。
隨機訪問索引
和普通的字節數據一樣,ByteBuf也是從0開始索引的。這就意味著第一個字節的索引永遠是0,而最後一個字節的索引則是capacity。舉個例子,當我們去遍歷緩沖中的所有字節的時候,我們可以按照如下方式來做:
ByteBuf buffer = ...; for (int i = 0; i < buffer.capacity(); i ++) { byteb = buffer.getByte(i); System.out.println((char) b); }
可以清楚的看到,其使用方式和遍歷字節數組一樣的做法。我們可以隨機的獲取緩沖區裏面的任意一個字節。
順序訪問索引
這個ByteBuf的實現中,有三個比較有意思的屬性,readerIndex,writerIndex,capacity,從字面意思上,我們可以理解為讀索引,寫索引,容量。下圖則展示了三個屬性之間的關系:
首先是readable bytes(可讀字節數組),裏面放置的是真實的數據,當使用帶有read或者是skip的方法來操作此數據內容的時候,都將導致readerIndex遞增。如果當前內容讀取完畢,沒有更多的內容可以讀取,那麽嘗試讀取將會拋出IndexOutOfBoundsException。默認情況下,一個新分配的緩沖區或者包裝的緩沖區或者復制的緩沖區,其readerIndex的初始值為0。示例讀取代碼如下:
// 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。示例寫入代碼如下:
// 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()方法來進行釋放,釋放前和釋放後的圖示示例如下:
釋放前:
釋放後:
需要註意的是,不同緩沖區的底層實現,可能會讓writable bytes裏面填充進完全不同的數據,所以使用此方法的時候,還請審慎。
你可以調用clear()
方法來重置readerIndex和writerIndex為0。此方法不會清理掉真實的數據,而是僅僅重置這兩個索引。
清理前:
清理後:
需要註意的是,此種情況下可能會覆蓋原有緩沖數據,使用的事情請謹慎。
搜索操作
簡單的單個字節搜索,可以使用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流的轉換。
略解ByteBuf