Tải bản đầy đủ - 0trang
Example 2-3. Utility routines for getting/putting unsigned values
* be assigning. putUnsignedByte takes a short argument, etc.
* @author Ron Hitchens (firstname.lastname@example.org)
public class Unsigned
public static short getUnsignedByte (ByteBuffer bb)
return ((short)(bb.get() & 0xff));
public static void putUnsignedByte (ByteBuffer bb, int value)
bb.put ((byte)(value & 0xff));
public static short getUnsignedByte (ByteBuffer bb, int position)
return ((short)(bb.get (position) & (short)0xff));
public static void putUnsignedByte (ByteBuffer bb, int position,
bb.put (position, (byte)(value & 0xff));
// --------------------------------------------------------------public static int getUnsignedShort (ByteBuffer bb)
return (bb.getShort() & 0xffff);
public static void putUnsignedShort (ByteBuffer bb, int value)
bb.putShort ((short)(value & 0xffff));
public static int getUnsignedShort (ByteBuffer bb, int position)
return (bb.getShort (position) & 0xffff);
public static void putUnsignedShort (ByteBuffer bb, int position,
bb.putShort (position, (short)(value & 0xffff));
// --------------------------------------------------------------public static long getUnsignedInt (ByteBuffer bb)
return ((long)bb.getInt() & 0xffffffffL);
public static void putUnsignedInt (ByteBuffer bb, long value)
bb.putInt ((int)(value & 0xffffffffL));
public static long getUnsignedInt (ByteBuffer bb, int position)
return ((long)bb.getInt (position) & 0xffffffffL);
public static void putUnsignedInt (ByteBuffer bb, int position,
bb.putInt (position, (int)(value & 0xffffffffL));
2.4.6 Memory-Mapped Buffers
Mapped buffers are byte buffers with data elements stored in a file and are accessed via
memory mapping. Mapped buffers are always direct and can be created only from a
FileChannel object. Usage of mapped buffers is similar to direct buffers, but
MappedByteBuffer objects possess many special characteristics unique to file access. For
this reason, I'm deferring discussion of mapped buffers to Section 3.4, which also
discusses file locking.
This chapter covered buffers, which live in the java.nio package. Buffer objects enable
the advanced I/O capabilities covered in the remaining chapters. These key buffer topics
were covered in this chapter:
Attributes that all buffers posses were covered in Section 2.1.1. These attributes
describe the current state of a buffer and affect how it behaves. In this section, we
also learned how to manipulate the state of buffers and how to add and remove
We learned how buffers are created in Section 2.2 and how to duplicate them in
Section 2.3. There are many types of buffers. The way a buffer is created
determines how and where it should be used.
While buffers can be created for any primitive data type other than boolean, byte
buffers have special features not shared by the other buffer types. Only byte
buffers can be used with channels (discussed in Chapter 3), and byte buffers offer
views of their content in terms of other data types. We also examined the issues
related to byte ordering. ByteBuffers were discussed in Section 2.4.
This concludes our visit with the menagerie of buffers in java.nio. The next stop on the
tour is java.nio.channels where you will encounter, not surprisingly, channels.
Channels interact with byte buffers and unlock the door to high-performance I/O. Hop
back on the bus, it's a short trip to our next stop.
Chapter 3. Channels
Brilliance! Sheer, unadulterated brilliance!
—Wile E. Coyote, Super Genius
Channels are the second major innovation of java.nio. They are not an extension or
enhancement, but a new, first-class Java I/O paradigm. They provide direct connections
to I/O services. A Channel is a conduit that transports data efficiently between byte
buffers and the entity on the other end of the channel (usually a file or socket).
A good metaphor for a channel is a pneumatic tube, the type used at drive-up bank-teller
windows. Your paycheck would be the information you're sending. The carrier would be
like a buffer. You fill the buffer (place your paycheck in the carrier), "write" the buffer to
the channel (drop the carrier into the tube), and the payload is carried to the I/O service
(bank teller) on the other end of the channel.
The response would be the teller filling the buffer (placing your receipt in the carrier) and
starting a channel transfer in the opposite direction (dropping the carrier back into the
tube). The carrier arrives on your end of the channel (a filled buffer is ready for you to
examine). You then flip the buffer (open the lid) and drain it (remove your receipt). You
drive away and the next object (bank customer) is ready to repeat the process using the
same carrier (Buffer) and tube (Channel) objects.
In most cases, channels have a one-to-one relationship with operating-system file
descriptors, or file handles. Although channels are more generalized than file descriptors,
most channels you will use on a regular basis are connected to open file descriptors. The
channel classes provide the abstraction needed to maintain platform independence but
still model the native I/O capabilities of modern operating systems.
Channels are gateways through which the native I/O services of the operating system can
be accessed with a minimum of overhead, and buffers are the internal endpoints used by
channels to send and receive data. (See Figure 3-1.)
Figure 3-1. Channels act as conduits to I/O services
As you can see from the UML class diagram in Figure 3-2, the inheritance relationships
of the channel classes are a bit more complicated than those of the buffer classes. The
interrelationships are more complex, and there are some dependencies on classes defined
in the java.nio.channels.spi subpackage. In this chapter, we'll make sense of this
tangle. The channels SPI is summarized in Appendix B.
Figure 3-2. The channel family tree
So without further ado, let's explore the exciting world of channels.
3.1 Channel Basics