说到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
首先是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
释放后:
须要注意的是,不一样缓冲区的底层实现,可能会让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流的转换。