A random and sequential accessible sequence of zero or more bytes (octets). This interface provides an abstract view for one or more primitive byte arrays (byte[]
) and NIO buffers .
It is recommended to create a new buffer using the helper methods in ChannelBuffers
rather than calling an individual implementation's constructor.
Just like an ordinary primitive byte array, ChannelBuffer
uses zero-based indexing . It means the index of the first byte is always 0
and the index of the last byte is always capacity - 1
. For example, to iterate all bytes of a buffer, you can do the following, regardless of its internal implementation:
ChannelBuffer buffer = ...; for (int i = 0; i < buffer.capacity(); i ++) { byte b = array.getByte(i); System.out.println((char) b); }
ChannelBuffer
provides two pointer variables to support sequential read and write operations - readerIndex
for a read operation and writerIndex
for a write operation respectively. The following diagram shows how a buffer is segmented into three areas by the two pointers:
+-------------------+------------------+------------------+ | discardable bytes | readable bytes | writable bytes | | | (CONTENT) | | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex <= writerIndex <= capacity
This segment is where the actual data is stored. Any operation whose name starts with read
or skip
will get or skip the data at the current readerIndex
and increase it by the number of read bytes. If the argument of the read operation is also a ChannelBuffer
and no destination index is specified, the specified buffer's readerIndex
is increased together.
If there's not enough content left, IndexOutOfBoundsException
is raised. The default value of newly allocated, wrapped or copied buffer's readerIndex
is 0
.
// Iterates the readable bytes of a buffer. ChannelBuffer buffer = ...; while (buffer.readable()) { System.out.println(buffer.readByte()); }
This segment is a undefined space which needs to be filled. Any operation whose name ends with write
will write the data at the current writerIndex
and increase it by the number of written bytes. If the argument of the write operation is also a ChannelBuffer
, and no source index is specified, the specified buffer's readerIndex
is increased together.
If there's not enough writable bytes left, IndexOutOfBoundsException
is raised. The default value of newly allocated buffer's writerIndex
is 0
. The default value of wrapped or copied buffer's writerIndex
is the capacity
of the buffer.
// Fills the writable bytes of a buffer with random integers. ChannelBuffer buffer = ...; while (buffer.writableBytes() >= 4) { buffer.writeInt(random.nextInt()); }
This segment contains the bytes which were read already by a read operation. Initially, the size of this segment is 0
, but its size increases up to the writerIndex
as read operations are executed. The read bytes can be discarded by callingdiscardReadBytes()
to reclaim unused area as depicted by the following diagram:
BEFORE discardReadBytes() +-------------------+------------------+------------------+ | discardable bytes | readable bytes | writable bytes | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex <= writerIndex <= capacity AFTER discardReadBytes() +------------------+--------------------------------------+ | readable bytes | writable bytes (got more space) | +------------------+--------------------------------------+ | | | readerIndex (0) <= writerIndex (decreased) <= capacity
Please note that there is no guarantee about the content of writable bytes after calling discardReadBytes()
. The writable bytes will not be moved in most cases and could even be filled with completely different data depending on the underlying buffer implementation.
You can set both readerIndex and writerIndex to 0 by calling clear() . It does not clear the buffer content (e.g. filling with 0
) but just clears the two pointers. Please also note that the semantic of this operation is different fromByteBuffer.clear()
.
BEFORE clear() +-------------------+------------------+------------------+ | discardable bytes | readable bytes | writable bytes | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex <= writerIndex <= capacity AFTER clear() +---------------------------------------------------------+ | writable bytes (got more space) | +---------------------------------------------------------+ | | 0 = readerIndex = writerIndex <= capacity
Various indexOf()
methods help you locate an index of a value which meets a certain criteria. Complicated dynamic sequential search can be done with ChannelBufferIndexFinder
as well as simple static single byte search.
There are two marker indexes in every buffer. One is for storing readerIndex
and the other is for storing writerIndex
. You can always reposition one of the two indexes by calling a reset method. It works in a similar fashion to the mark and reset methods in InputStream
except that there's no readlimit
.
You can create a view of an existing buffer by calling either duplicate()
, slice()
or slice(int, int)
. A derived buffer will have an independent readerIndex
, writerIndex
and marker indexes, while it shares other internal data representation, just like a NIO buffer does.
In case a completely fresh copy of an existing buffer is required, please call copy()
method instead.
Various toByteBuffer()
and toByteBuffers()
methods convert a ChannelBuffer
into one or more NIO buffers. These methods avoid buffer allocation and memory copy whenever possible, but there's no guarantee that memory copy will not be involved or that an explicit memory copy will be involved.
Various toString(String)
methods convert a ChannelBuffer
into a String
. Please note that toString()
is not a conversion method.
Please refer to ChannelBufferInputStream
and ChannelBufferOutputStream
.