Java NIO(17)AsynchronousFileChannel非同期ファイルチャネル

5277 ワード

Java 7では、AsynchronousFileChannelがJava NIOに追加される.AsynchronousFileChannelは、ファイルからデータを読み込み、ファイルに書き込むことができます.このチュートリアルでは、AsynchronousFileChannelの使用方法について説明します.
非同期ファイルチャネルの作成
静的メソッドopen()でAsynchronousFileChannelを作成できます.ここでは、AsynchronousFileChannelを作成する例を示します.
Path path = Paths.get("data/test.xml");

AsynchronousFileChannel fileChannel =
    AsynchronousFileChannel.open(path, StandardOpenOption.READ);

Open()メソッドの最初のパラメータは、AsynchronousFileChannelに関連付けられたファイルのPathインスタンスを指します.
2番目のパラメータは、AsynchronousFileChannelが下位ファイルでどのような操作を実行するかを示す1つ以上の開いたオプションです.この例ではStandardOpenOptionを使用しています.READ、これは、読むためにファイルが開かれることを意味します.
データの読み取り
AsynchronousFileChannelからは、2つの方法でデータを読み込むことができます.データを読み込む各メソッドは、AsynchronousFileChannelのread()メソッドの1つを呼び出します.この2つのデータの読み取り方法については、以下の章で説明します.
Futureでデータを読む
AsynchronousFileChannelからデータを読み込む最初の方法は、Futureに戻るread()メソッドを呼び出すことです.これはread()メソッドを呼び出す方法です.
Future operation = fileChannel.read(buffer, 0);

read()メソッドのこのバージョンは、ByteBufferを最初のパラメータとして使用します.AsynchronousFileChannelから読み込んだデータがこのByteBufferに読み込まれます.2番目のパラメータは、ファイルで読み取りを開始するバイトの位置です.
read()メソッドは、読み取り操作が完了しなくてもすぐに返されます.read()メソッドが返すFutureインスタンスのisDone()メソッドを呼び出すことで、読み取り操作がいつ完了するかを確認できます.
ここでは、このバージョンのread()メソッドをどのように使用するかを示すより長い例です.
AsynchronousFileChannel fileChannel = 
    AsynchronousFileChannel.open(path, StandardOpenOption.READ);

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;

Future operation = fileChannel.read(buffer, position);

while(!operation.isDone());

buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println(new String(data));
buffer.clear();

この例では、AsynchronousFileChannelを作成し、パラメータとしてread()メソッドにByteBufferを渡す方法を作成し、位置は0である.read()を呼び出すと、返されるFutureのisDone()メソッドがtrueを返すまでループします.もちろん、CPUを非常に効果的に使用するわけではありませんが、なぜか読み取り操作が完了するまで待つ必要があります.
読み出しが完了すると、ByteBufferにデータを読み込み、文字列に印刷してSystemに印刷する.out.
CompletionHandlerによるデータの読み込み
AsynchronousFileChannelからデータを読み込む第2の方法は、CompletionHandlerをパラメータとするread()メソッドバージョンを呼び出すことです.このread()メソッドを呼び出す方法は、次のとおりです.
fileChannel.read(buffer, position, buffer, new CompletionHandler() {
    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        System.out.println("result = " + result);

        attachment.flip();
        byte[] data = new byte[attachment.limit()];
        attachment.get(data);
        System.out.println(new String(data));
        attachment.clear();
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {

    }
});

読み込みが完了すると、CompletionHandlerのcompleted()メソッドが呼び出されます.完了()メソッドのパラメータとしてIntegerが読み込まれたバイト数を教え、read()メソッドの「添付ファイル」に渡す.「添付ファイル」はread()メソッドの3番目のパラメータです.この場合、データも読み込まれるのがByteBufferです.追加するオブジェクトを自由に選択できます.
読み込み操作に失敗すると、CompletionHandlerのfailed()メソッドが呼び出されます.
データの書き込み
読むように、AsynchronousFileChannelに2つの方法でデータを書き込むことができます.各書き込み方法は、AsynchronousFileChannelのwrite()メソッドの1つを呼び出します.この2つのデータの書き方は、次の章で説明します.
Writing Data Via a Future
AsynchronousFileChannelでは、非同期でデータを書き込むこともできます.完全なJava AsynchronousFileChannelの書き込み例です.
Path path = Paths.get("data/test-write.txt");
AsynchronousFileChannel fileChannel = 
    AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;

buffer.put("test data".getBytes());
buffer.flip();

Future operation = fileChannel.write(buffer, position);
buffer.clear();

while(!operation.isDone());

System.out.println("Write done");

まず、書き込みモードでAsynchronousFileChannelを開きます.その後、ByteBufferを作成し、いくつかのデータを書き込みます.その後、ByteBufferのデータをファイルに書き込みます.最後に、この例では、戻ってきたFutureをチェックして、書き込みがいつ完了するかを確認します.
コードが動作する前に、ファイルがすでに存在する必要があります.ファイルが存在しない場合、write()メソッドはjavaを放出します.nio.file.NoSuchFileException異常.
次のコードを使用して、Pathが指すファイルが存在することを確認できます.
if(!Files.exists(path)){
    Files.createFile(path);
}

Writing Data Via a CompletionHandler
CompletionHandlerを使用してAsynchronousFileChannelにデータを書き込み、Futureではなく書き込みが完了したことを伝えることもできます.次に、CompletionHandlerを使用してAsynchronousFileChannelにデータを書き込む例を示します.
Path path = Paths.get("data/test-write.txt");
if(!Files.exists(path)){
    Files.createFile(path);
}
AsynchronousFileChannel fileChannel = 
    AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;

buffer.put("test data".getBytes());
buffer.flip();

fileChannel.write(buffer, position, buffer, new CompletionHandler() {

    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        System.out.println("bytes written: " + result);
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        System.out.println("Write failed");
        exc.printStackTrace();
    }
});

書き込みが完了すると、CompletionHandlerのcompleted()メソッドが呼び出されます.何らかの理由で書き込みに失敗した場合、failed()メソッドが呼び出されます.
ByteBufferがどのように添付ファイルとしてCompletionHandlerメソッドのオブジェクトに渡されるかに注意してください.