Chapter 6. New I/O
One of the major new features of Java 1.4 is a new Input/Output (I/O)
architecture, intended for servers and other applications that
require high-performance I/O. Features of this New I/O API include:
- Network channels (the New I/O version of sockets) can be placed in
nonblocking mode. - Multiple nonblocking channels can be multiplexed
with a Selector object. This means that it is no
longer necessary to create a new thread to monitor each network
connection. - Files can be
memory mapped. - Files, and sections of
files,
can be locked to prevent concurrent read and write access. - The new Charset class and related classes give better
control over character-to-byte encoding and byte-to-character
decoding. - The java.util.regex package supports text matching
with Perl 5-style regular expressions. Although regular expressions
are not directly related to I/O, they were developed under the
umbrella of the same Java Specification Request (JSR) and are often
considered to be part of the New I/O API.
This chapter demonstrates all of these features. To understand the
examples, an overview of the New I/O API
is in order. Except for the java.util.regex
package already mentioned, the bulk of the New I/O is in
java.nio and its subpackages.
java.nio defines the
Buffer class and various concrete subclasses,
such as ByteBuffer and
CharBuffer for holding sequences of bytes,
characters, and other primitive types. All actual I/O is done with
byte buffers, but values of other primitive types can be inserted
into byte buffers, and byte buffers and their subranges can be viewed
as buffers of other types, such as IntBuffer or
FloatBuffer.While the original java.io architecture is based
on a stream abstraction (InputStream,
OutputStream, Reader, and
Writer), the new I/O architecture is based on the
Channel abstraction defined in
java.nio.channels. A
ReadableByteChannel
transfers bytes from some source (such as a socket or a file) into a
ByteBuffer. A
WritableByteChannel
transfers bytes from a ByteBuffer to some
destination (such as a socket or file). All
channels are
byte-oriented: there is no such interface as
WritableCharChannel, for example.Because channels work exclusively with bytes, any I/O or networking
code that involves character data requires the writer to encode
characters into bytes and the reader to decode those bytes back into
characters. The java.nio.charset package defines a
Charset class to represent a character encoding.
Charset and related classes define methods for
converting bytes in a ByteBuffer to characters in
a CharBuffer and vice versa.A
FileChannel
is a read/write conduit to a file, which provides random-access,
memory-mapping, locking, and bulk-transfer facilities. A
SocketChannel
is a read/write channel built on top of a
java.net.Socket.
ServerSocketChannel provides the
Channel abstraction on top of
java.net.ServerSocket. The important thing about
SocketChannel and
ServerSocketChannel
is that they are "selectable": they
can be placed in nonblocking mode and multiplexed with a
Selector object. This allows a single thread to
block until activity occurs on any one of the channels it is
interested in. This is a basic feature of most operating systems,
which, until Java 1.4, has been absent from the Java API. It
dramatically improves the scalability of servers written in Java
because it no longer requires a new thread to block on each client
socket. SocketChannel and
ServerSocketChannel perform stream-based
networking. For UDP datagram-based networking,
java.nio.channels provides the
DatagramChannel,
which, like the socket channel classes, may be multiplexed with a
Selector.In addition to file and socket channels,
java.nio.channels also includes the
Pipe class and its inner channel classes,
Pipe.SourceChannel
and
Pipe.SinkChannel,
for interthread communication. Like the socket channels, these
channel types can be multiplexed with a Selector.
Their use is similar to other channels, but they are not demonstrated
in this chapter.The new channel-based I/O architecture is more efficient and
powerful, but also more complicated, than the original stream-based
API. High-performance servers need the new API, but many other
applications can and should continue to use the simpler streams of
the java.io and java.net
packages. The New I/O API is also valuable to applications that need
regular expressions or want to take advantage of the advanced file
features of the FileChannel class, such as file
locking. This chapter begins by demonstrating basic file and regular
expression capabilities. It then creates a
Tokenizer implementation (see Example 2-8) for arbitrary channels, and demonstrates
advanced byte-to-character conversion with
java.nio.charset. Finally, it moves on to
networking, demonstrating client and server applications using
SocketChannel and
ServerSocketChannel. The networking examples
include simple programs and more advanced programs that multiplex
channels with a Selector.