[ Team LiB ] Previous Section Next Section

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.

    [ Team LiB ] Previous Section Next Section