标签:ack 简单 reac [] tps str htm max enc
说到ByteBuf,我们并不陌生,官网给的解释为,一个可以进行随机访问或者是顺序访问的字节集合,它是NIO buffers缓冲的底层抽象。既然是底层抽象,那么我们就可以基于其衍生出很多的具体实现出来,事实上,netty中的很多缓冲组件都是基于此抽象类做的扩展。
随机访问索引
和普通的字节数据一样,ByteBuf也是从0开始索引的。这就意味着第一个字节的索引永远是0,而最后一个字节的索引则是capacity。举个例子,当我们去遍历缓冲中的所有字节的时候,我们可以按照如下方式来做:
ByteBuf buffer = ...; for (int i = 0; i < buffer.capacity(); i ++) { byte b = 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流的转换。
标签:ack 简单 reac [] tps str htm max enc
原文地址:https://www.cnblogs.com/scy251147/p/10366626.html