您的位置:首页 > 编程语言 > Java开发

Netty ByteBuf

2017-07-20 13:27 162 查看
本文是使用Google翻译自: http://netty.io/4.1/api/io/netty/buffer/ByteBuf.html

类结构

io.netty.buffer

Class ByteBuf

java.lang.Object

io.netty.buffer.ByteBuf

所有实现的接口:

ReferenceCounted,Comparable < ByteBuf >

直接已知子类:

AbstractByteBuf,EmptyByteBuf,SwappedByteBuf

public abstract class ByteBuf

extends Object

implements ReferenceCounted,Comparable < ByteBuf >

零个或多个字节(八位字节)的随机和顺序可访问序列。该接口提供一个或多个原始字节数组(byte[])和NIO缓冲区的抽象视图。

创建缓冲区

建议使用
Unpooled
类的方法创建一个新的缓冲区, 而不是调用其实现的构造函数。

随机访问索引

就像普通的原始字节数组一样,ByteBuf使用 零索引。这意味着第一个字节的索引为0,最后一个字节的索引总capacity - 1。例如,要迭代缓冲区的所有字节,无论内部实现如何,都可以执行以下操作:

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


顺序访问索引

ByteBuf提供两个指针变量来支持顺序读写操作 - 分别readerIndex用于读操作和writerIndex写操作。下图显示了两个指针如何将缓冲区分割成三个区域:

+-------------------+------------------+------------------+
| discardable bytes |  readable bytes  |  writable bytes  |
|                   |     (CONTENT)    |                  |
+-------------------+------------------+------------------+
|                   |                  |                  |
0      <=      readerIndex   <=   writerIndex    <=    capacity


可读字节(实际内容)

该段是实际数据存储的地方。任何名称以读或跳过开头的操作都可以在当前的readerIndex中获取或跳过数据,并通过读取字节的数量来增加它。如果读操作的参数也是ByteBuf,并且没有指定目标索引,那么指定的缓冲区的writerIndex将会一起增加(也就是参数ByteBuf)。

如果剩下可读的内容还不够,IndexOutOfBoundsException将被抛出。默认值通过wrapped或copied新分配ByteBuf的readerIndex是0。

//迭代缓冲区的可读字节。
ByteBuf buffer = ...;
while (buffer.isReadable()) {
System.out.println(buffer.readByte());
}


可写字节

该段是一个未定义的空间,需要填充。名称开头为write的任何操作将当前数据写入缓冲区, writerIndex将增加其写入字节数。如果写操作的参数也是ByteBuf,并且没有指定源索引,则指定的缓冲区 readerIndex一起增加。

如果没有足够的可写字节剩余,IndexOutOfBoundsException 则被抛出。默认新分配的缓冲区writerIndex是0。通过wrapped或copied分配的缓冲区writerIndex=capacity。

//用随机整数填充缓冲区的可写字节。
ByteBuf buffer = ...;
while (buffer.maxWritableBytes() >= 4) {
buffer.writeInt(random.nextInt());
}


可舍弃的字节

这个段包含读取操作已经读取的字节。最初,这个段的大小是0,但是随着读操作的执行,它的大小会增加到writerIndex。通过调用discardReadBytes()回收未使用的区域可以丢弃读取的字节,如下图所示:

调用discardReadBytes()之前

+-------------------+------------------+------------------+
| discardable bytes |  readable bytes  |  writable bytes  |
+-------------------+------------------+------------------+
|                   |                  |                  |
0      <=      readerIndex   <=   writerIndex    <=    capacity


调用discardReadBytes()之后

+------------------+--------------------------------------+
|  readable bytes  |    writable bytes (got more space)   |
+------------------+--------------------------------------+
|                  |                                      |


readerIndex (0) <= writerIndex (decreased) <= capacity

请注意,调用discardReadBytes()后不能保证可写字节数据内容。在大多数情况下,可写字节数据将不会被移动,甚至可以根据底层缓冲区实现填充完全不同的数据。

清除缓冲区索引

调用clear()将可以同时设置readerIndex,writerIndex为0。它不清除缓冲区内容(例如填充0),但只重置两个指针。还请注意,这个操作的语义不同Buffer.clear()。

BEFORE clear()

+-------------------+------------------+------------------+
| discardable bytes |  readable bytes  |  writable bytes  |
+-------------------+------------------+------------------+
|                   |                  |                  |
0      <=      readerIndex   <=   writerIndex    <=    capacity


AFTER clear()

+---------------------------------------------------------+
|             writable bytes (got more space)             |
+---------------------------------------------------------+
|                                                         |
0 = readerIndex = writerIndex            <=            capacity


搜索操作

对于简单的单字节搜索,请使用
indexOf(int, int, byte)
bytesBefore(int, int, byte)
bytesBefore(byte)
在处理NUL终止字符串时特别有用。对于复杂的搜索,使用
forEachByte(int, int, ByteProcessor)
ByteProcessor
实施。

final String v = "safkjhaswororldldworldororldldhellodkhsafhhello";
final String key="world";
final ByteBuf buffer = Unpooled.buffer();
buffer.writeBytes(v.getBytes());
int index = buffer.forEachByte(new ByteProcessor() {
byte[] bytes = key.getBytes();
int index = 0;
@Override
public boolean process(byte value) throws Exception {
if(value==bytes[index]){
index++;
if (index==bytes.length){
return false;
}
}else{
index=0;
if(value==bytes[
4000
index]){
index++;
if (index==bytes.length){
return false;
}
}else{
index=0;
}
}
return true;
}
});
System.out.println(index);
Assert.assertEquals(v.indexOf(key)+key.length()-1,index);


标记并复位

每个缓冲区中有两个标记索引。一个用于存储 readerIndex,另一个用于存储 writerIndex。您可以随时通过调用重置方法重新定位其中一个索引。它的工作方式与标记和重置方法类似,InputStream除了没有 readlimit。

派生缓冲区

您可以通过调用以下方法之一来创建现有缓冲区的视图:

duplicate()
共享数据缓冲区,独立维护readerindex和writerindex

slice()
共享数据缓冲区中可读的一部分,独立维护readerindex和writerindex

slice(int, int)
共享数据缓冲区中可读的一部分,独立维护readerindex和writerindex

readSlice(int)
read
表示会增加源ByteBuf的readerindex

retainedDuplicate()
retained
表示会增加引用计数

retainedSlice()


retainedSlice(int, int)


readRetainedSlice(int)


衍生缓冲器将有一个独立的readerIndex, writerIndex并且标记索引,而这股其他内部数据表示,就像一个NIO缓冲器一样。

如果需要现有缓冲区的全新副本,请调用copy()方法。

非保留和保留的派生缓冲区

需要注意的是duplicate(),slice(),slice(int, int)并且readSlice(int)不调用retain()上返回的派生缓冲,因而其引用计数将不会增加。如果你需要创建一个增加引用计数派生缓冲,可以考虑使用retainedDuplicate(), retainedSlice(),retainedSlice(int, int)和readRetainedSlice(int)它可能返回产生较少的垃圾一个缓冲区实现。

转换到现有的JDK类型

字节数组

如果ByteBuf由字节数组(即byte[])支持,则可以通过该array()方法直接访问它。要确定缓冲区是否由字节数组支持,hasArray()应该使用。

System.out.println(Unpooled.directBuffer().hasArray());(false)


NIO缓冲区

如果一个ByteBuf可以转换成ByteBuffer共享其内容的NIO (即视图缓冲区),那么可以通过该nioBuffer()方法得到它。要确定缓冲区是否可以转换为NIO缓冲区,请使用nioBufferCount()。

字符串

各种toString(Charset)方法将ByteBuf 转换成String。请注意,这和Object.toString()不是一种转换方法。

I / O流

请参考ByteBufInputStream和 ByteBufOutputStream。

try(ByteBufInputStream bufInputStream = new ByteBufInputStream(Unpooled.copiedBuffer("abcedfg".getBytes()))){
while(bufInputStream.available()>0){
System.out.println((char)bufInputStream.read());
}
}catch (Exception e){
e.printStackTrace();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Javadoc 翻译 Netty ByteBuf