読み込み・書き込みするのなら
読み込み
- ReadableByteChannel#read
public int read(ByteBuffer dst) throws IOException
チャネルからバッファに読み込みを行います。読み込んだ結果はByteBufferオブジェクトのdstに格納されます。格納されるのはdstのpositionからlimitまでです。
readメソッドの戻り値は読み込んだバイト数です。チャネルが最後に達したら戻り値は-1になります。
ストリームでは読み込みを行っているときに、他のスレッドからストリームがクローズされたりインターラプトされた時の動作が明確になっていませんでしたが、New I/Oではこのような事象に対する例外が定義されています。
図1に非同期クローズのシーケンスを示します。非同期クローズされた場合、AsynchronousCloseException例外が発生します。同様に他のスレッドからThread#interruptメソッドを使用してインターラプトされたときにはClosedByInterruptException例外が発生します。
また、クローズしているチャネルに対してreadメソッドをコールした場合、ClosedChannelException例外が発生します。
ただし、これらの例外はすべてIOExceptionクラスの派生クラスなので、IOExceptionに対応する例外処理を記述するだけでもかまいません。
書き込み
- WritableByteChannel#write
public int write(ByteBuffer src) throws IOException
バッファの内容をチャネルに書き込みます。書き込むのはsrcのpositionからlimitまでです。writeメソッドを抜けるとsrcのpositionは書き込んだバイト数だけ移動します。
戻り値は書き込んだバイト数です。
writeメソッドもreadメソッドと同様に、非同期クローズや非同期インターラプトされたときにはAsynchronousCloseException例外、ClosedByInterruptException例外が発生します。また、チャネルがクローズしていた場合もreadメソッドと同じで、ClosedChannelException例外が発生します。
リスト1にreadメソッドとwriteメソッドを使ったファイルのコピーの例を示します(一部、例外処理を省略してあります)。この例ではByteChannelインタフェースをインプリメントしているFileChannelクラスを使用しています。
例ではwhileループの中で1000バイトづつreadメソッドを使用して読み込みます。読み込んだ結果はByteBufferオブジェクトに格納されるので、それをwriteメソッドを使用して書き込んでいます。
readメソッドで読み込んだときにbufferのlimitまでデータが書き込まれなくとも、ByteBuffer#flipメソッドを使用すれば、bufferに書きこまれた位置までlimitが移動し、positionは0に移動します。writeメソッドはByteBufferオブジェクトのpositionからlimitまでを書き込むので、読み込んだバイト数を気にせずに書き込みを行うことができます。
ByteChannel readChannel = new RandomAccessFile(dstFilename, "r").getChannel(); ByteChannel writeChannel = new RandomAccessFile(srcFilename, "w").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1000); while (true) { buffer.clear(); try { if (readChannel.read(buffer) == -1) { break; } buffer.flip(); writeChannel.write(buffer); } catch (AsynchronousCloseException ex) { // 非同期クローズに対応する例外処理 } catch (ClosedByInterruptException ex) { // 非同期インターラプトに対応する例外処理 } catch (ClosedChannelException ex) { // クローズしたチャネルに処理を行った場合の例外処理 } catch (IOException ex) { // IOException に対応する例外処理 } } readChannel.close(); writeChannel.close();
クローズ
- Channel#close
public void close() throws IOException
チャネルのクローズを行います。チャネルをクローズすると、もとのストリームもクローズされます。
チャネルはマルチスレッドでの使用を考慮されています。このため、複数のスレッドでチャネルを使用しているときに、他のスレッドで読み込み・書き込みを行っているときにクローズをしてしまうと、読み込み・書き込みを行っているスレッドでAsynchronousCloseException例外が発生します。
コラム より大容量の入出力
ByteChannelはByteBufferを使用して、高速に読み込み・書き込みを行うことができます。しかし、より大容量のデータの入出力を行うためのインタフェースもNew I/Oには用意されています。
ScatteringByteChannelインタフェースが読み込み、GatheringByteChannelインタフェースが書き込みを行います。双方ともメソッドが
public long read(ByteBuffer[] buffer) throws IOException public long write(ByteBuffer[] buffer) throws IOException
のようにByteBufferの配列になっており、一度に大量のデータを読み込み・書き込みすることができます。
FileChannelやSocketChannelはByteChannelインタフェースだけでなく、この2つのインタフェースを実装しているので入出力するデータの量に応じて使い分けることができます。
(2003.03)