epubjs
Version:
Render ePub documents in the browser, across many devices
359 lines (354 loc) • 79.4 kB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>The NIO Package</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="The NIO Package"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-12-SECT-5"/>The NIO Package</h1></div></div></div><p>We are now going to complete our introduction to core Java I/O
facilities by returning to the <a id="I_indexterm12_id761367" class="indexterm"/><code class="literal">java.nio</code> package. The
name NIO stands for “New I/O” and, as we saw earlier in this chapter in
our discussion of <code class="literal">java.nio.file</code>, one
aspect of NIO is simply to update and enhance features of the legacy
<code class="literal">java.io</code> package. Much of the general
NIO functionality does indeed overlap with existing APIs. However, NIO was
first introduced to address specific issues of scalability for large
systems, especially in networked applications. The following section
outlines the basic elements of NIO, which center on working with
<span class="emphasis"><em>buffers</em></span> and <span class="emphasis"><em>channels</em></span>.</p><div class="sect2" title="Asynchronous I/O"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.1"/>Asynchronous I/O</h2></div></div></div><p><a id="idx10678" class="indexterm"/> <a id="idx10714" class="indexterm"/> <a id="idx10732" class="indexterm"/>Most of the need for the NIO package was driven by the
desire to add <span class="emphasis"><em>nonblocking</em></span> and
<span class="emphasis"><em>selectable</em></span> I/O to Java. Prior to NIO, most read and
write operations in Java were bound to threads and were forced to block
for unpredictable amounts of time. Although certain APIs such as Sockets
(which we’ll see in <a class="xref" href="ch13.html" title="Chapter 13. Network Programming">Chapter 13</a>) provided
specific means to limit how long an I/O call could take, this was a
workaround to compensate for the lack of a more general mechanism. In
many languages, even those without threading, I/O could still be done
efficiently by setting I/O streams to a nonblocking mode and testing
them for their readiness to send or receive data. In a nonblocking mode,
a read or write does only as much work as can be done
immediately—filling or emptying a buffer and then returning. Combined
with the ability to test for readiness, this allows a single-threaded
application to continuously service many channels efficiently. The main
thread “selects” a stream that is ready and works with it until it
blocks and then moves on to another. On a single-processor system, this
is fundamentally equivalent to using multiple threads. It turns out that
this style of processing has scalability advantages even when using a
pool of threads (rather than just one). We’ll discuss this in detail in
<a class="xref" href="ch13.html" title="Chapter 13. Network Programming">Chapter 13</a>when we
discuss networking and building servers that can handle many
clients simultaneously.</p><p>In addition to nonblocking and selectable I/O, the NIO package
enables closing and interrupting I/O operations asynchronously. As
discussed in <a class="xref" href="ch09.html" title="Chapter 9. Threads">Chapter 9</a>, prior to NIO there was
no reliable way to stop or wake up a thread blocked in an I/O operation.
With NIO, threads blocked in I/O operations always wake up when
interrupted or when the channel is closed by anyone. Additionally, if
you interrupt a thread while it is blocked in an NIO operation, its
channel is automatically closed. (Closing the channel because the thread
is interrupted might seem too strong, but usually it’s the right thing
to do.)<a id="I_indexterm12_id761505" class="indexterm"/><a id="I_indexterm12_id761512" class="indexterm"/><a id="I_indexterm12_id761519" class="indexterm"/></p></div><div class="sect2" title="Performance"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.2"/>Performance</h2></div></div></div><p><a id="I_indexterm12_id761533" class="indexterm"/> <a id="idx10741" class="indexterm"/>Channel I/O is designed around the concept of
<span class="emphasis"><em>buffers</em></span>, which are a sophisticated form of array,
tailored to working with communications. The NIO package supports the
concept of <span class="emphasis"><em>direct buffers—</em></span>buffers that maintain
their memory outside the Java VM in the host operating system. Because
all real I/O operations ultimately have to work with the host OS by
maintaining the buffer space there, some operations can be made much
more efficient. Data moving between two external endpoints can be
transferred without first copying it into Java and back out.</p></div><div class="sect2" title="Mapped and Locked Files"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.3"/>Mapped and Locked Files</h2></div></div></div><p><a id="I_indexterm12_id761575" class="indexterm"/> <a id="I_indexterm12_id761586" class="indexterm"/> <a id="I_indexterm12_id761592" class="indexterm"/> <a id="idx10740" class="indexterm"/>NIO provides two general-purpose file-related features not
found in <code class="literal">java.io</code>: memory-mapped files
and file locking. We’ll discuss memory-mapped files later, but suffice
it to say that they allow you to work with file data as if it were all
magically resident in memory. File locking supports the concept of
shared and exclusive locks on regions of files—useful for concurrent
access by multiple applications.</p></div><div class="sect2" title="Channels"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.4"/>Channels</h2></div></div></div><p><a id="idx10684" class="indexterm"/> <a id="idx10716" class="indexterm"/> <a id="idx10735" class="indexterm"/>While <code class="literal">java.io</code> deals
with streams, <code class="literal">java.nio</code> works with
channels. A <span class="emphasis"><em>channel</em></span> is an endpoint for
communication. Although in practice channels are similar to streams, the
underlying notion of a channel is more abstract and primitive. Whereas
streams in <code class="literal">java.io</code> are defined in
terms of input or output with methods to read and write bytes, the basic
channel interface says nothing about how communications happen. It
simply has the notion of being open or closed, supported via the methods
<code class="literal">isOpen()</code> and <code class="literal">close()</code>. Implementations of channels for
files, network sockets, or arbitrary devices then add their own methods
for operations, such as reading, writing, or transferring data. The
following channels are provided by NIO:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p><code class="literal">FileChannel</code></p></li><li class="listitem"><p><code class="literal">Pipe.SinkChannel</code>, <code class="literal">Pipe.SourceChannel</code></p></li><li class="listitem"><p><code class="literal">SocketChannel</code>, <code class="literal">ServerSocketChannel</code>, <code class="literal">DatagramChannel</code></p></li></ul></div><p>We’ll cover <code class="literal">FileChannel</code> in this
chapter. The <code class="literal">Pipe</code> channels are simply
the channel equivalents of the <code class="literal">java.io
Pipe</code> facilities. We’ll talk about <code class="literal">Socket</code> and <code class="literal">Datagram</code> channels in <a class="xref" href="ch13.html" title="Chapter 13. Network Programming">Chapter 13</a>. Additionally, in Java 7 there are now
asynchronous versions of both the file and socket channels: <code class="literal">AsynchronousFileChannel</code>, <code class="literal">AsynchronousSocketChannel</code>, <code class="literal">AsynchronousServerSocketChannel</code>, and <code class="literal">AsynchronousDatagramChannel</code>. These
asynchronous versions essentially buffer all of their operations through
a thread pool and report results back through an asynchronous API. We’ll
talk about the asynchronous file channel later in this chapter.</p><p>All these basic channels implement the <code class="literal">ByteChannel</code> interface, designed for channels
that have read and write methods like I/O streams. <code class="literal">ByteChannel</code>s read and write <code class="literal">ByteBuffer</code>s, however, as opposed to plain byte
arrays.</p><p>In addition to these channel implementations, you can bridge
channels with <code class="literal">java.io</code> I/O streams and
readers and writers for interoperability. However, if you mix these
features, you may not get the full benefits and performance offered by
the NIO package.<a id="I_indexterm12_id761832" class="indexterm"/><a id="I_indexterm12_id761839" class="indexterm"/><a id="I_indexterm12_id761846" class="indexterm"/></p></div><div class="sect2" title="Buffers"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.5"/>Buffers</h2></div></div></div><p><a id="idx10715" class="indexterm"/>Most of the utilities of the <code class="literal">java.io</code> and <code class="literal">java.net</code> packages operate on byte arrays. The
corresponding tools of the NIO package are built around <a id="idx10683" class="indexterm"/><code class="literal">ByteBuffer</code>s (with
character-based buffer <a id="I_indexterm12_id761901" class="indexterm"/><code class="literal">CharBuffer</code> for text).
Byte arrays are simple, so why are buffers necessary? They serve several
purposes:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>They formalize the usage patterns for buffered data, provide
for things like read-only buffers, and keep track of read/write
positions and limits within a large buffer space. They also provide
a mark/reset facility like that of <code class="literal">java.io.BufferedInputStream</code>.</p></li><li class="listitem"><p>They provide additional APIs for working with raw data
representing primitive types. You can create buffers that “view”
your byte data as a series of larger primitives, such as <code class="literal">short</code>s, <code class="literal">int</code>s, or <code class="literal">float</code>s. The most general type of data
buffer, <code class="literal">ByteBuffer</code>, includes
methods that let you read and write all primitive types just like
<code class="literal">DataOutputStream</code> does for
streams.</p></li><li class="listitem"><p>They abstract the underlying storage of the data, allowing for
special optimizations by Java. Specifically, buffers may be
allocated as direct buffers that use native buffers of the host
operating system instead of arrays in Java’s memory. The NIO
<code class="literal">Channel</code> facilities that work with
buffers can recognize direct buffers automatically and try to
optimize I/O to use them. For example, a read from a file channel
into a Java byte array normally requires Java to copy the data for
the read from the host operating system into Java’s memory. With a
direct buffer, the data can remain in the host operating system,
outside Java’s normal memory space until and unless it is
needed.</p></li></ul></div><div class="sect3" title="Buffer operations"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-12-SECT-5.5.1"/>Buffer operations</h3></div></div></div><p><a id="idx10681" class="indexterm"/> <a id="idx10733" class="indexterm"/>A buffer is a subclass of a <a id="I_indexterm12_id762016" class="indexterm"/><code class="literal">java.nio.Buffer</code>
object. The base <code class="literal">Buffer</code> class is
something like an array with state. It does not specify what type of
elements it holds (that is for subtypes to decide), but it does define
functionality that is common to all data buffers. A <code class="literal">Buffer</code> has a fixed size called its
<span class="emphasis"><em>capacity</em></span>. Although all the standard <code class="literal">Buffer</code>s provide “random access” to their
contents, a <code class="literal">Buffer</code> generally
expects to be read and written sequentially, so <code class="literal">Buffer</code>s maintain the notion of a
<span class="emphasis"><em>position</em></span> where the next element is read or
written. In addition to position, a <code class="literal">Buffer</code> can maintain two other pieces of
state information: a <span class="emphasis"><em>limit</em></span>, which is a position
that is a “soft” limit to the extent of a read or write, and a
<span class="emphasis"><em>mark</em></span>, which can be used to remember an earlier
position for future recall.</p><p>Implementations of <code class="literal">Buffer</code> add
specific, typed get and put methods that read and write the buffer
contents. For example, <code class="literal">ByteBuffer</code>
is a buffer of bytes and it has <a id="I_indexterm12_id762094" class="indexterm"/><code class="literal">get()</code> and <a id="I_indexterm12_id762107" class="indexterm"/><code class="literal">put()</code> methods that
read and write bytes and arrays of bytes (along with many other useful
methods we’ll discuss later). Getting from and putting to the <code class="literal">Buffer</code> changes the position marker, so the
<code class="literal">Buffer</code> keeps track of its contents
somewhat like a stream. Attempting to read or write past the limit
marker generates a <a id="I_indexterm12_id762132" class="indexterm"/><code class="literal">BufferUnderflowException</code> or <a id="I_indexterm12_id762144" class="indexterm"/><code class="literal">BufferOverflowException</code>,
respectively.</p><p>The mark, position, limit, and capacity values always obey
the
following formula:</p><a id="I_programlisting12_id762167"/><pre class="programlisting"> <code class="n">mark</code> <code class="o"><=</code> <code class="n">position</code> <code class="o"><=</code> <code class="n">limit</code> <code class="o"><=</code> <code class="n">capacity</code></pre><p>The position for reading and writing the <code class="literal">Buffer</code> is always between the mark, which
serves as a lower bound, and the limit, which serves as an upper
bound. The capacity represents the physical extent of the buffer
space.</p><p>You can set the position and limit markers explicitly with the
<a id="I_indexterm12_id762186" class="indexterm"/><code class="literal">position()</code> and
<a id="I_indexterm12_id762197" class="indexterm"/><code class="literal">limit()</code> methods.
Several convenience methods are provided for common usage patterns.
The <a id="I_indexterm12_id762208" class="indexterm"/><code class="literal">reset()</code> method sets
the position back to the mark. If no mark has been set, an <code class="literal">InvalidMarkException</code> is thrown. The
<a id="I_indexterm12_id762225" class="indexterm"/><code class="literal">clear()</code> method resets
the position to <code class="literal">0</code> and makes the
limit the capacity, readying the buffer for new data (the mark is
discarded). Note that the <code class="literal">clear()</code>
method does not actually do anything to the data in the buffer; it
simply changes the position markers.</p><p>The <code class="literal">flip()</code> method is used for
the common pattern of writing data into the buffer and then reading it
back out. <a id="I_indexterm12_id762257" class="indexterm"/><code class="literal">flip</code> makes the
current position the limit and then resets the current position to
<code class="literal">0</code> (any mark is thrown away), which
saves having to keep track of how much data was read. Another method,
<code class="literal">rewind()</code>, simply resets the
position to <code class="literal">0</code>, leaving the limit
alone. You might use it to write the same size data again. Here is a
snippet of code that uses these methods to read data from a channel
and write it to two channels:</p><a id="I_12_tt817"/><pre class="programlisting"> <code class="n">ByteBuffer</code> <code class="n">buff</code> <code class="o">=</code> <code class="o">...</code>
<code class="k">while</code> <code class="o">(</code> <code class="n">inChannel</code><code class="o">.</code><code class="na">read</code><code class="o">(</code> <code class="n">buff</code> <code class="o">)</code> <code class="o">></code> <code class="mi">0</code> <code class="o">)</code> <code class="o">{</code> <code class="c1">// position = ?</code>
<code class="n">buff</code><code class="o">.</code><code class="na">flip</code><code class="o">();</code> <code class="c1">// limit = position; position = 0;</code>
<code class="n">outChannel</code><code class="o">.</code><code class="na">write</code><code class="o">(</code> <code class="n">buff</code> <code class="o">);</code>
<code class="n">buff</code><code class="o">.</code><code class="na">rewind</code><code class="o">();</code> <code class="c1">// position = 0</code>
<code class="n">outChannel2</code><code class="o">.</code><code class="na">write</code><code class="o">(</code> <code class="n">buff</code> <code class="o">);</code>
<code class="n">buff</code><code class="o">.</code><code class="na">clear</code><code class="o">();</code> <code class="c1">// position = 0; limit = capacity</code>
<code class="o">}</code></pre><p>This might be confusing the first time you look at it because
here, the read from the <code class="literal">Channel</code> is
actually a write to the <code class="literal">Buffer</code> and
vice versa. Because this example writes all the available data up to
the limit, either <code class="literal">flip()</code> or
<code class="literal">rewind()</code> have the same effect in
this case.<a id="I_indexterm12_id762328" class="indexterm"/><a id="I_indexterm12_id762335" class="indexterm"/></p></div><div class="sect3" title="Buffer types"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-12-SECT-5.5.2"/>Buffer types</h3></div></div></div><p><a id="idx10682" class="indexterm"/> <a id="idx10734" class="indexterm"/>As stated earlier, various buffer types add get and put
methods for reading and writing specific data types. Each of the Java
primitive types has an associated buffer type: <a id="I_indexterm12_id762377" class="indexterm"/><code class="literal">ByteBuffer</code>, <a id="I_indexterm12_id762390" class="indexterm"/><code class="literal">CharBuffer</code>,
<a id="I_indexterm12_id762400" class="indexterm"/><code class="literal">ShortBuffer</code>,
<a id="I_indexterm12_id762411" class="indexterm"/><code class="literal">IntBuffer</code>, <a id="I_indexterm12_id762421" class="indexterm"/><code class="literal">LongBuffer</code>,
<a id="I_indexterm12_id762432" class="indexterm"/><code class="literal">FloatBuffer</code>, and
<a id="I_indexterm12_id762443" class="indexterm"/><code class="literal">DoubleBuffer</code>. Each
provides get and put methods for reading and writing its type and
arrays of its type. Of these, <code class="literal">ByteBuffer</code> is the most flexible. Because it
has the “finest grain” of all the buffers, it has been given a full
complement of get and put methods for reading and writing all the
other data types as well as <code class="literal">byte</code>.
Here are some <code class="literal">ByteBuffer</code>
methods:</p><a id="I_12_tt818"/><pre class="programlisting"> <code class="kt">byte</code> <code class="nf">get</code><code class="o">()</code>
<code class="kt">char</code> <code class="nf">getChar</code><code class="o">()</code>
<code class="kt">short</code> <code class="nf">getShort</code><code class="o">()</code>
<code class="kt">int</code> <code class="nf">getInt</code><code class="o">()</code>
<code class="kt">long</code> <code class="nf">getLong</code><code class="o">()</code>
<code class="kt">float</code> <code class="nf">getFloat</code><code class="o">()</code>
<code class="kt">double</code> <code class="nf">getDouble</code><code class="o">()</code>
<code class="kt">void</code> <code class="nf">put</code><code class="o">(</code><code class="kt">byte</code> <code class="n">b</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">put</code><code class="o">(</code><code class="n">ByteBuffer</code> <code class="n">src</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">put</code><code class="o">(</code><code class="kt">byte</code><code class="o">[]</code> <code class="n">src</code><code class="o">,</code> <code class="kt">int</code> <code class="n">offset</code><code class="o">,</code> <code class="kt">int</code> <code class="n">length</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">put</code><code class="o">(</code><code class="kt">byte</code><code class="o">[]</code> <code class="n">src</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">putChar</code><code class="o">(</code><code class="kt">char</code> <code class="n">value</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">putShort</code><code class="o">(</code><code class="kt">short</code> <code class="n">value</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">putInt</code><code class="o">(</code><code class="kt">int</code> <code class="n">value</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">putLong</code><code class="o">(</code><code class="kt">long</code> <code class="n">value</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">putFloat</code><code class="o">(</code><code class="kt">float</code> <code class="n">value</code><code class="o">)</code>
<code class="kt">void</code> <code class="nf">putDouble</code><code class="o">(</code><code class="kt">double</code> <code class="n">value</code><code class="o">)</code></pre><p>As we said, all the standard buffers also support random access.
For each of the aforementioned methods of <code class="literal">ByteBuffer</code>, an additional form takes an
index; for example:</p><a id="I_12_tt819"/><pre class="programlisting"> <code class="n">getLong</code><code class="o">(</code> <code class="kt">int</code> <code class="n">index</code> <code class="o">)</code>
<code class="n">putLong</code><code class="o">(</code> <code class="kt">int</code> <code class="n">index</code><code class="o">,</code> <code class="kt">long</code> <code class="n">value</code> <code class="o">)</code></pre><p>But that’s not all. <code class="literal">ByteBuffer</code> can also provide “views” of
itself as any of the coarse-grained types. For example, you can fetch
a <code class="literal">ShortBuffer</code> view of a <code class="literal">ByteBuffer</code> with the <a id="I_indexterm12_id762525" class="indexterm"/><code class="literal">asShortBuffer()</code>
method. The <code class="literal">ShortBuffer</code> view is
<span class="emphasis"><em>backed</em></span> by the <code class="literal">ByteBuffer</code>, which means that they work on
the same data, and changes to either one affect the other. The view
buffer’s extent starts at the <code class="literal">ByteBuffer</code>’s current position, and its
capacity is a function of the remaining number of bytes, divided by
the new type’s size. (For example, <code class="literal">short</code>s consume two bytes each, <code class="literal">float</code>s four, and <code class="literal">long</code>s and <code class="literal">double</code>s take eight.) View buffers are
convenient for reading and writing large blocks of a contiguous type
within a <code class="literal">ByteBuffer</code>.</p><p><code class="literal">CharBuffer</code>s are interesting
as well, primarily because of their integration with <code class="literal">String</code>s. Both <code class="literal">CharBuffer</code>s and <code class="literal">String</code>s implement the <a id="I_indexterm12_id762609" class="indexterm"/><code class="literal">java.lang.CharSequence</code> interface. This is
the interface that provides the standard <code class="literal">charAt()</code> and <code class="literal">length()</code> methods. Because of this, newer
APIs (such as the <code class="literal">java.util.regex</code>
package) allow you to use a <code class="literal">CharBuffer</code> or a <code class="literal">String</code> interchangeably. In this case, the
<code class="literal">CharBuffer</code> acts like a modifiable
<code class="literal">String</code> with user-configurable,
logical start and end positions.<a id="I_indexterm12_id762660" class="indexterm"/><a id="I_indexterm12_id762667" class="indexterm"/></p></div><div class="sect3" title="Byte order"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-12-SECT-5.5.3"/>Byte order</h3></div></div></div><p><a id="I_indexterm12_id762681" class="indexterm"/> <a id="I_indexterm12_id762689" class="indexterm"/>Because we’re talking about reading and writing types
larger than a byte, the question arises: in what order do the bytes of
multibyte values (e.g., <code class="literal">short</code>s and
<code class="literal">int</code>s) get written? There are two
camps in this world: “big endian” and “little endian.”<sup>[<a id="learnjava3-CHP-12-FN-3" href="#ftn.learnjava3-CHP-12-FN-3" class="footnote">36</a>]</sup> Big endian means that the most significant bytes come
first; little endian is the reverse. If you’re writing binary data for
consumption by some native application, this is important.
Intel-compatible computers use little endian, and many workstations
that run Unix use big endian. The <a id="I_indexterm12_id762750" class="indexterm"/><code class="literal">ByteOrder</code> class
encapsulates the choice. You can specify the byte order to use with
the <code class="literal">ByteBuffer order()</code> method,
using the identifiers <code class="literal">ByteOrder.BIG_ENDIAN</code> and <code class="literal">ByteOrder.LITTLE_ENDIAN</code> like so:</p><a id="I_12_tt820"/><pre class="programlisting"> <code class="n">byteArray</code><code class="o">.</code><code class="na">order</code><code class="o">(</code> <code class="n">ByteOrder</code><code class="o">.</code><code class="na">BIG_ENDIAN</code> <code class="o">);</code></pre><p>You can retrieve the native ordering for your platform using the
static <code class="literal">ByteOrder.nativeOrder()</code>
method. (I know you’re curious.)</p></div><div class="sect3" title="Allocating buffers"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-12-SECT-5.5.4"/>Allocating buffers</h3></div></div></div><p><a id="I_indexterm12_id762803" class="indexterm"/> <a id="I_indexterm12_id762812" class="indexterm"/>You can create a buffer either by allocating it
explicitly using <a id="I_indexterm12_id762823" class="indexterm"/><code class="literal">allocate()</code> or by
wrapping an existing plain Java array type. Each buffer type has a
static <code class="literal">allocate()</code> method that takes
a capacity (size) and also a <code class="literal">wrap()</code>
method that takes an existing array:</p><a id="I_12_tt821"/><pre class="programlisting"> <code class="n">CharBuffer</code> <code class="n">cbuf</code> <code class="o">=</code> <code class="n">CharBuffer</code><code class="o">.</code><code class="na">allocate</code><code class="o">(</code> <code class="mi">64</code><code class="o">*</code><code class="mi">1024</code> <code class="o">);</code></pre><p>A direct buffer is allocated in the same way, with the
<a id="I_indexterm12_id762858" class="indexterm"/><code class="literal">allocateDirect()</code>
method:</p><a id="I_12_tt822"/><pre class="programlisting"> <code class="n">ByteBuffer</code> <code class="n">bbuf</code> <code class="o">=</code> <code class="n">ByteBuffer</code><code class="o">.</code><code class="na">allocateDirect</code><code class="o">(</code> <code class="mi">64</code><code class="o">*</code><code class="mi">1024</code> <code class="o">);</code>
<code class="n">ByteBuffer</code> <code class="n">bbuf2</code> <code class="o">=</code> <code class="n">ByteBuffer</code><code class="o">.</code><code class="na">wrap</code><code class="o">(</code> <code class="n">someExistingArray</code> <code class="o">);</code></pre><p>As we described earlier, direct buffers can use operating system
memory structures that are optimized for use with some kinds of I/O
operations. The tradeoff is that allocating a direct buffer is a
little slower and heavier weight operation than a plain buffer, so you
should try to use them for longer-term buffers.<a id="I_indexterm12_id762884" class="indexterm"/></p></div></div><div class="sect2" title="Character Encoders and Decoders"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.6"/>Character Encoders and Decoders</h2></div></div></div><p><a id="idx10685" class="indexterm"/> <a id="idx10717" class="indexterm"/> <a id="idx10736" class="indexterm"/>Character encoders and decoders turn characters into raw
bytes and vice versa, mapping from the Unicode standard to particular
encoding schemes. Encoders and decoders have long existed in Java for
use by <code class="literal">Reader</code> and <code class="literal">Writer</code> streams and in the methods of the
<code class="literal">String</code> class that work with byte
arrays. However, early on there was no API for working with encoding
explicitly; you simply referred to encoders and decoders wherever
necessary by name as a <code class="literal">String</code>. The
<a id="I_indexterm12_id762962" class="indexterm"/><code class="literal">java.nio.charset</code>
package formalized the idea of a Unicode character set encoding with the
<a id="I_indexterm12_id762973" class="indexterm"/><code class="literal">Charset</code> class.</p><p>The <code class="literal">Charset</code> class is a factory
for <code class="literal">Charset</code> instances, which know how
to encode character buffers to byte buffers and decode byte buffers to
character buffers. You can look up a character set by name with the
static <code class="literal">Charset.forName()</code> method and
use it in conversions:</p><a id="I_12_tt823"/><pre class="programlisting"> <code class="n">Charset</code> <code class="n">charset</code> <code class="o">=</code> <code class="n">Charset</code><code class="o">.</code><code class="na">forName</code><code class="o">(</code><code class="s">"US-ASCII"</code><code class="o">);</code>
<code class="n">CharBuffer</code> <code class="n">charBuff</code> <code class="o">=</code> <code class="n">charset</code><code class="o">.</code><code class="na">decode</code><code class="o">(</code> <code class="n">byteBuff</code> <code class="o">);</code> <code class="c1">// to ascii</code>
<code class="n">ByteBuffer</code> <code class="n">byteBuff</code> <code class="o">=</code> <code class="n">charset</code><code class="o">.</code><code class="na">encode</code><code class="o">(</code> <code class="n">charBuff</code> <code class="o">);</code> <code class="c1">// and back</code></pre><p>You can also test to see if an encoding is available with the
static <code class="literal">Charset.isSupported()</code>
method.</p><p>The following character sets are guaranteed to be supplied:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p><a id="I_indexterm12_id763029" class="indexterm"/>US-ASCII</p></li><li class="listitem"><p><a id="I_indexterm12_id763037" class="indexterm"/>ISO-8859-1</p></li><li class="listitem"><p><a id="I_indexterm12_id763046" class="indexterm"/> <a id="I_indexterm12_id763053" class="indexterm"/>UTF-8</p></li><li class="listitem"><p><a id="I_indexterm12_id763062" class="indexterm"/>UTF-16BE</p></li><li class="listitem"><p><a id="I_indexterm12_id763070" class="indexterm"/>UTF-16LE</p></li><li class="listitem"><p><a id="I_indexterm12_id763079" class="indexterm"/>UTF-16</p></li></ul></div><p>You can list all the encoders available on your platform using the
static <a id="I_indexterm12_id763088" class="indexterm"/><code class="literal">availableCharsets()</code>
method:</p><a id="I_12_tt824"/><pre class="programlisting"> <code class="n">Map</code> <code class="n">map</code> <code class="o">=</code> <code class="n">Charset</code><code class="o">.</code><code class="na">availableCharsets</code><code class="o">();</code>
<code class="n">Iterator</code> <code class="n">it</code> <code class="o">=</code> <code class="n">map</code><code class="o">.</code><code class="na">keySet</code><code class="o">().</code><code class="na">iterator</code><code class="o">();</code>
<code class="k">while</code> <code class="o">(</code> <code class="n">it</code><code class="o">.</code><code class="na">hasNext</code><code class="o">()</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">it</code><code class="o">.</code><code class="na">next</code><code class="o">()</code> <code class="o">);</code></pre><p>The result of <code class="literal">availableCharsets()</code> is a map because character
sets may have “aliases” and appear under more than one name.</p><p>In addition to the buffer-oriented classes of the <code class="literal">java.nio</code> package, the <code class="literal">InputStreamReader</code> and <code class="literal">OutputStreamWriter</code> bridge classes of the
<code class="literal">java.io</code> package have been updated to
work with <code class="literal">Charset</code> as well. You can
specify the encoding as a <code class="literal">Charset</code>
object or by name.</p><div class="sect3" title="CharsetEncoder and CharsetDecoder"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-12-SECT-5.6.1"/>CharsetEncoder and CharsetDecoder</h3></div></div></div><p><a id="idx10687" class="indexterm"/> <a id="idx10688" class="indexterm"/>You can get more control over the encoding and decoding
process by creating an instance of <code class="literal">CharsetEncoder</code> or <code class="literal">CharsetDecoder</code> (a codec) with the <code class="literal">Charset newEncoder()</code> and <code class="literal">newDecoder()</code> methods. In the previous
snippet, we assumed that all the data was available in a single
buffer. More often, however, we might have to process data as it
arrives in chunks. The encoder/decoder API allows for this by
providing more general <a id="I_indexterm12_id763207" class="indexterm"/><code class="literal">encode()</code> and
<a id="I_indexterm12_id763218" class="indexterm"/><code class="literal">decode()</code> methods that
take a flag specifying whether more data is expected. The codec needs
to know this because it might have been left hanging in the middle of
a multibyte character conversion when the data ran out. If it knows
that more data is coming, it does not throw an error on this
incomplete conversion. In the following snippet, we use a decoder to
read from a <code class="literal">ByteBuffer bbuff</code> and
accumulate character data into a <code class="literal">CharBuffer
cbuff</code>:</p><a id="I_12_tt825"/><pre class="programlisting"> <code class="n">CharsetDecoder</code> <code class="n">decoder</code> <code class="o">=</code> <code class="n">Charset</code><code class="o">.</code><code class="na">forName</code><code class="o">(</code><code class="s">"US-ASCII"</code><code class="o">).</code><code class="na">newDecoder</code><code class="o">();</code>
<code class="kt">boolean</code> <code class="n">done</code> <code class="o">=</code> <code class="kc">false</code><code class="o">;</code>
<code class="k">while</code> <code class="o">(</code> <code class="o">!</code><code class="n">done</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">bbuff</code><code class="o">.</code><code class="na">clear</code><code class="o">();</code>
<code class="n">done</code> <code class="o">=</code> <code class="o">(</code> <code class="n">in</code><code class="o">.</code><code class="na">read</code><code class="o">(</code> <code class="n">bbuff</code> <code class="o">)</code> <code class="o">==</code> <code class="o">-</code><code class="mi">1</code> <code class="o">);</code>
<code class="n">bbuff</code><code class="o">.</code><code class="na">flip</code><code class="o">();</code>
<code class="n">decoder</code><code class="o">.</code><code class="na">decode</code><code class="o">(</code> <code class="n">bbuff</code><code class="o">,</code> <code class="n">cbuff</code><code class="o">,</code> <code class="n">done</code> <code class="o">);</code>
<code class="o">}</code>
<code class="n">cbuff</code><code class="o">.</code><code class="na">flip</code><code class="o">();</code>
<code class="c1">// use cbuff. . .</code></pre><p>Here, we look for the end of input condition on the <code class="literal">in</code> channel to set the flag <code class="literal">done</code>. Note that we take advantage of the
<code class="literal">flip()</code> method on <code class="literal">ByteBuffer</code> to set the limit to the amount of
data read and reset the position, setting us up for the decode
operation in one step. The <code class="literal">encode()</code>
and <code class="literal">decode()</code> methods also return a
result object, <code class="literal">CoderResult</code>, that
can determine the progress of encoding (we do not use it in the
previous snippet). The methods <a id="I_indexterm12_id763297" class="indexterm"/><code class="literal">isError()</code>, <a id="I_indexterm12_id763308" class="indexterm"/><code class="literal">isUnderflow()</code>, and
<a id="I_indexterm12_id763318" class="indexterm"/><code class="literal">isOverflow()</code> on the
<code class="literal">CoderResult</code> specify why encoding
stopped: for an error, a lack of bytes on the input buffer, or a full
output buffer, respectively.<a id="I_indexterm12_id763336" class="indexterm"/><a id="I_indexterm12_id763343" class="indexterm"/><a id="I_indexterm12_id763350" class="indexterm"/><a id="I_indexterm12_id763357" class="indexterm"/><a id="I_indexterm12_id763364" class="indexterm"/></p></div></div><div class="sect2" title="FileChannel"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-12-SECT-5.7"/>FileChannel</h2></div></div></div><p><a id="idx10718" class="indexterm"/>Now that we’ve covered the basics of channels and buffers,
it’s time to look at a real channel type. The <code class="literal">FileChannel</code> is the NIO equivalent of the
<code class="literal">java.io.RandomAccessFile</code> , but it
provides several core new features in addition to some performance
optimizations. In particular, use a <code class="literal">FileChannel</code> in place of a plain <code class="literal">java.io</code> file stream if you wish to use file
locking, memory-mapped file access, or highly optimized data transfer
between files or between file and network channels.</p><p>A <code class="literal">FileChannel</code> can be created
for a <code class="literal">Path</code> using the static <code class="literal">FileChannel</code><code class="literal">open()</code> method.</p><a id="I_programlisting12_id763442"/><pre class="programlisting"> <code class="n">FileSystem</code> <code class="n">fs</code> <code class="o">=</code> <code class="n">FileSystems</code><code class="o">.</code><code class="na">getDefault</code><code class="o">();</code>
<code class="n">Path</code> <code class="n">p</code> <code class="o">=</code> <code class="n">fs</code><code class="o">.</code><code class="na">getPath</code><code class="o">(</code> <code class="s">"/tmp/foo.txt"</code> <code class="o">);</code>
<code class="c1">// Open default for reading</code>
<code class="k">try</code> <code class="o">(</code> <code class="n">FileChannel</code> <code class="n">channel</code> <code class="o">=</code> <code class="n">FileChannel</code><code class="o">.</code><code class="na">open</code><code class="o">((</code> <code class="n">p</code> <code class="o">)</code> <code class="o">)</code> <code class="o">{</code>
<code class="o">...</code>
<code class="o">}</code>
<code class="c1">// Open with options for writing</code>
<code class="kn">import</code> <code class="nn">static</code> <code class="n">java</code><code class="o">.</code><code class="na">nio</code><code class="o">.</code><code class="na">file</code><code class="o">.</code><code class="na">StandardOpenOption</code><code class="o">.*;</code>
<code class="k">try</code> <code class="o">(</code> <code class="n">FileChannel</code> <code class="n">channel</code> <code class="o">=</code> <code class="n">FileChannel</code><code class="o">.</code><code class="na">open</code><code class="o">(</code> <code class="n">p</code><code class="o">,</code> <code class="n">WRITE</code><code class="o">,</code> <code class="n">APPEND</code><code class="o">,</code> <code class="o">...</code> <code class="o">)</code> <code class="o">)</code> <code class="o">{</code>
<code class="o">...</code>
<code class="o">}</code></pre><p>By default, <code class="literal">open()</code> creates a
read-only channel for the file. We can open a channel for writing or
appending and control other more advanced features such as atomic create
and data syncing by passing additional options as shown in the second
part of the previous example. <a class="xref" href="ch12s06.html#t1204" title="Table 12-4. java.nio.file.StandardOpenOption">Table 12-4</a> summarizes these
options.<a id="I_indexterm12_id763466" class="indexterm"/><a id="I_indexterm12_id763471" class="indexterm"/><a id="I_indexterm12_id763477" class="indexterm"/><a id="I_indexterm12_id763482" class="indexterm"/><a id="I_indexterm12_id763488" class="indexterm"/><a id="I_indexterm12_id763493" class="indexterm"/><a id="I_indexterm12_id763499" class="indexterm"/><a id="I_indexterm12_id763504" class="indexterm"/><a id="I_indexterm12_id763510" class="indexterm"/><a id="I_indexterm12_id763515" class="indexterm"/></p><div class="table"><a id="t1204"/><p class="title">Table 12-4. java.nio.file.StandardOpenOption</p><div class="table-contents"><table summary="java.nio.file.StandardOpenOption" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; "><colgroup><col/><col/></colgroup><thead><tr><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">Option</th><th style="border-bottom: 0.5pt solid ; ">Description</th></tr></thead><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">READ</code>, <code class="literal">WRITE</code></td><td style="border-bottom: 0.5pt solid ; ">Open the file for read-only or write-only (default is
read-only). Use both for read-write.</td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">APPEND</code></td><td style="border-bottom: 0.5pt solid ; ">Open the file for writing; all writes are positioned at
the end of the file.</td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">CREATE</code></td><td style="border-bottom: 0.5pt solid ; ">Use with <code class="literal">WRITE</code> to open
the file and create it if needed.</td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">CREATE_NEW</code></td><td style="border-bottom: 0.5pt solid ; ">Use with <code class="literal">WRITE</code> to
create a file atomically; failing if the file already
exists.</td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">DELETE_ON_CLOSE</code></td><td style="border-bottom: 0.5pt solid ; ">Attempt to delete the file when it is closed or, if open,
when the VM exits.</td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">SYNC</code>, <code class="literal">DSYNC</code></td><td style="border-bottom: 0.5pt solid ; ">Wherever possible, guarantee that write operations block
until all data is written to storage. <code class="literal">SYNC</code> does this for all file changes
including data and metadata (attributes) whereas <code class="literal">DSYNC</code> only adds this requirement for
the data content of the file.</td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; "><code class="literal">SPARSE</code></td><td style="border-bottom: 0.5pt solid ; ">Use when creating a new file, requests the file be
sparse. On filesystems where this is supported, a sparse file
handles very large, mostly empty files without allocating as
much real storage for empty portions.</td></tr><tr><td style="border-right: 0.5pt solid ; "><code class="literal">TRUNCATE_EXISTING</code></td><td style="">Use <code class="literal">WRITE</code> on an
existing file, set the file length to zero upon opening
it.</td></tr></tbody></table></div></div><p>A <code class="literal">FileChannel</code> can also be
constructed from a classic <code class="literal">FileInputStream</code>, <code class="literal">FileOutputStream</code>, or <code class="literal">RandomAccessFile</code>:</p><a id="I_12_tt826"/><pre class="programlisting"> <code class="n">FileChannel</code> <code class="n">readOnlyFc</code> <code class="o">=</code> <code class="k">new</code> <code class="n">FileInputStream</code><code class="o">(</code><code class="s">"file.txt"</code><code class="o">).</code><code class="na">getChannel</code><code class="o">();</code>
<code class="n">FileChannel</code> <code class="n">readWriteFc</code> <code class="o">=</code> <code class="k">new</code> <code class="n">RandomAccessFile</code><code class="o">(</code><code class="s">"file.txt"</code><code class="o">,</code> <code class="s">"rw"</code><code class="o">)</code>
<code class="o">.</code><code class="na">getChannel</code><code class="o">();</code></pre><p><code class="literal">FileChannel</code>s created from these
file input and output streams are read-only or write-only, respectively.
To get a read/write <code class="literal">FileChannel</code>, you
must construct a <code class="literal">RandomAccessFile</code>
with read/write permissions, as in the previous example.</p><p>Using a <code class="literal">FileChannel</code> is just
like a <code class="literal">RandomAccessFile</code>, but it works
with <code class="literal">ByteBuffer</code> instead of byte
arrays:</p><a id="I_12_tt827"/><pre class="programlisting"> <code class="n">ByteBuffer</code> <code class="n">bbuf</code> <code class="o">=</code> <code class="n">ByteBuffer</code><code class="o">.</code><code class="na">allocate</code><code class="o">(</code> <code class="o">...</code> <code class="o">);</code>
<code class="n">bbuf</code><code class="o">.</code><code class="na">clear</code><code class="o">();</code>
<code class="n">readOnlyFc</code><code class="o">.</code><code class="na">position</code><code class="o">(</code> <code class="n">index</code> <code class="o">);</code>
<code class="n">readOnlyFc</code><code class="o">.</code><code class="na">read</code><code class="o">(</code> <code class="n">bbuf</code> <code class="o">);