Netty_ByteBuf基本用法二
上一篇http://my.oschina.net/xinxingegeya/blog/283227
#1 Segment(段) that holds bytes that can be discarded(废弃的) as they were read before
#2 Segment that holds the actual readable content that was not read yet
#3 Segment that contains the left space of the buffer and so to which more bytes can be written
The discardable bytes segment contains the bytes that were already read by a read operation and so may be discarded. Initially, the size of this segment is 0, but its size increases up to the writerIndex as read operations are executed. This only includes read operations; get operations do not move the readerIndex. The read bytes can be discarded by calling discardReadBytes()to reclaim unused space.
Figure 5.4 shows what the segments of a ByteBuflook like before discardReadBytes() is called.
#1 Segment that holds bytes that can be discarded as they was read before
#2 Segment that holds the actual readable content that was not read yet
#3 Segment that contains the left space of the buffer and so to which more bytes can be written
As you can see, the discardable bytes segment contains some space that is ready for reuse. This can be achieved by calling discardReadBytes().
Figure 5.5 shows how the call of discardReadBytes() will affect the segments.
#1 Segment that holds the actual readable content that was not read yet. This starts now on index 0
#3 Segment that contains the left space of the buffer and so to which more bytes can be written. This is now bigger as it growed by the space that was hold by the discardable bytes before
Note that theres no guarantee about the content of writable bytes after calling discardReadBytes(). The writable bytes wont be moved in most cases and could even be filled with completely different data depending on the underlying buffer implementation. Also, you may be tempted(动心) to frequently call discardReadBytes() to provide the ByteBuf with more writable space again. Be aware that discardReadBytes() will most likely involve(涉及) a memory copy as it needs to move the readable bytes (content) to the start of the ByteBuf. Such an operation isnt free and may affect(影响) performance, so only use it if you need it and will benefit from it. Thus would be for example if you need to free up memory as soon as possible.
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 ByteBufand no destination index is specified, the specified destination buffer's writerIndexis increased together. If there's not enough content left, IndexOutOfBoundExceptionis raised. The default value of newly allocated, wrapped, or copied buffer's readerIndexis 0. The following listing shows how to read all readable data.
Listing 5.8 Read data
// Iterates the readable bytes of a buffer. ByteBuf buffer = ...; while (buffer.readable()) { System.out.println(buffer.readByte()); }
This segment is an undefined space which needs to be filled. Any operation whose name starts 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 ByteBufand no source index is specified, the specified buffer's readerIndexis increased together. If there's not enough writable bytes left, IndexOutOfBoundException is raised. The default value of newly allocated buffer's writerIndexis 0. The following listing shows an example that fills the buffer with random intvalues until it runs out of space.
Listing 5.9 Write data
// Fills the writable bytes of a buffer with random integers. ByteBuf buffer = ...; while (buffer.writableBytes() >= 4) { buffer.writeInt(random.nextInt()); }
You can set both readerIndex and writerIndex to 0 by calling clear(). It doesnt clear the buffers content (for example, filling with 0) but clears the two pointers. Please note that the semantics of this operation are different from the JDKs ByteBuffer.clear(). Lets look at its functionality.
Figure 5.6 shows a ByteBufwith the three different segments.
#1 Segment that holds bytes that can be discarded as they were read before
#2 Segment that holds the actual readable content that was not read yet
#3 Segment that contains the left space of the buffer and so to which more bytes can be written
As before, it contains three segments. Youll see this change once clear() is called. Figure
5.7 shows the ByteBufafter clear()is used.
#1 Segment is now as big as the capacity of the ByteBuf, so everything is writable
Compared to discardReadBytes(), the clear() operation is cheap, because it adjusts pointers and doesnt need to copy any memory.
Various indexOf() methods help you locate an index of a value which meets a certain criteria. Complicated dynamic sequential search can be done with ByteBufProcessorimplementations as well as simple static single-byte search. If youre decoding variable length data such as NULL-terminated string, youll find the bytesBefore(byte)method useful. Let's imagine you've written an application, which has to integrate with flash sockets, which uses NULL-terminated content. Using the bytesBefore()method, you can easily consume data from Flash without manually readying every byte in the data to check for NULL bytes. Without the ByteBufProcessoryou would need to do all this work by yourself. Also it is more efficient as it needs less bound checks during processing.
As stated before, there are two marker indexes in every buffer. One is for storing readerIndexand 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 an InputStreamexcept that there are no read limits. Also, you can move them to an exact index by calling readerIndex(int) or writerIndex(int).Be aware that trying to set the readerIndex or writerIndex to an invalid position will cause an IndexOutOfBoundException.
To create a view of an existing buffer, call duplicate(), slice(), slice(int, int), readOnly(), or order(ByteOrder). A derived buffer has an independent readerIndex, writerIndex, and marker indexes, but it shares other internal data representation the way a NIO ByteBufferdoes. Because it shares the internal data representation, its cheap to create and is the preferred way if, for example, you need a slice of a ByteBufin an operation. If a fresh copy of an existing buffer is required, use the copy() or copy(int, int) method instead. The following listing shows how to work with a slice of a ByteBuf.
Listing 5.10 Slice a ByteBuf
Charset utf8 = Charset.forName(ìUTF-8ì); ByteBuf buf = Unpooled.copiedBuffer(ìNetty in Action rocks!ì, utf8); #1 ByteBuf sliced = buf.slice(0, 14); #2 System.out.println(sliced.toString(utf8); #3 buf.setByte(0, (byte) íJí); #4 assert buf.get(0) == sliced.get(0); #5
#1 Create ByteBuf which holds bytes for given string
#2 Create new slice of ByteBuf which starts at index 0 and ends at index 14
#3 Contains Netty in Action
#4 Update byte on index 0
#5 Wont fail as both ByteBuf share the same content and so modifications to one of them are visible on the other too
Now lets look at how to create a copy of a ByteBuf and how that differs from a slice. The following listing shows how to work with a copy of a ByteBuf.
There are two main types of read/write operations:
Index based get/set operations that set or get bytes on a given index.
Read/write operations that either read bytes from the current index and increase them or write to the current index and increase it.
Lets review the relative operations first; Ill mention only the most popular for now. For a complete overview, refer to the API docs.
Charset utf8 = Charset.forName(ìUTF-8ì); ByteBuf buf = Unpooled.copiedBuffer(ìNetty in Action rocks!ì, utf8); #1 System.out.println((char) buf.getByte(0)); #2 // #3 int readerIndex = buf.readerIndex(); int writerIndex = buf.writerIndex(); buf.setByte(0, (byte) íBí); #4 System.out.println((char) buf.getByte(0)); #5 // #6 assert readerIndex = buf.readerIndex(); assert writerIndex = buf.writerIndex();
#1 Create a new ByteBuf which holds the bytes for the given String
#2 Prints out the first char which is N
#3 Store the current readerIndex and writerIndex
#4 Update the byte on index 0 with the char B
#5 Prints out the first char which is B now as I updated it before
#6 Check that the readerIndex and writerIndex did not change which is true as relative operations never modify the indexes.
Charset utf8 = Charset.forName(ìUTF-8ì); ByteBuf buf = Unpooled.copiedBuffer(ìNetty in Action rocks!ì, utf8); #1 System.out.println((char) buf.readByte()); #2 // int readerIndex = buf.readerIndex(); #3 int writerIndex = buf.writerIndex(); #4 buf.writeByte( (byte) í?í); #5 // #6 assert readerIndex = buf.readerIndex(); assert writerIndex != buf.writerIndex();
#1 Create ByteBuf which holds bytes for given string
#2 Prints first char N
#3 Store current readerIndex and writerIndex
#4 Update byte on index 0 with char B
#5 Prints first char B that I updated
#6 Check readerIndex and writerIndex didnt change
There are other useful operations that Ihavent mentioned yet, but they often come in handy, depending on your use case. Table 5.5 gives an overview of them and explains what they do.
isReadable()
Returns true if at least one byte can be read.
isWritable()
Returns true if at least one byte can be written.
readableBytes()
Returns the number of bytes that can be read.
writablesBytes()
Returns the number of bytes that can be written.
capacity()
Returns the number of bytes that the ByteBufcan hold. After this it will try to expand again until maxCapacity() is reached.
maxCapacity()
Returns the maximal number of bytes the ByteBufcan hold.
hasArray()
Returns true if the ByteBufis backed by a byte array.
array()
Returns the byte array if the ByteBufis backed by a byte array, otherwise throws an UnsupportedOperationException.
You may need to work with normal objects called POJOs. These need to be stored and retrieved later. Often, its important to keep the order of the contained objects. For this purpose, Netty provides another data container called MessageBuf.
====END====