鍍金池/ 教程/ Java/ 17. Java NIO AsynchronousFileChannel異步文件通道
16. Java NIO Files
03. Java NIO Channel通道
06. Java NIO Channel to Channel Transfers通道傳輸接口
11. Java NIO: Non-blocking Server非阻塞服務器
01. Java NIO 教程
17. Java NIO AsynchronousFileChannel異步文件通道
09. Java NIO SocketChannel套接字通道
07. Java NIO Selector選擇器
08. Java NIO FileChannel文件通道
02. Java NIO 概覽
04. Java NIO Buffer緩沖區(qū)
10. Java NIO ServerSocketChannel服務端套接字通道
05. Java NIO Scatter / Gather
14. Java NIO vs. IO
13.Java NIO Pipe管道
12. Java NIO DatagramChannel數(shù)據(jù)報通道
15.Java NIO Path路徑

17. Java NIO AsynchronousFileChannel異步文件通道

原文鏈接:http://tutorials.jenkov.com/java-nio/asynchronousfilechannel.html

Java7中新增了AsynchronousFileChannel作為nio的一部分。AsynchronousFileChannel使得數(shù)據(jù)可以進行異步讀寫。下面將介紹一下AsynchronousFileChannel的使用。

創(chuàng)建AsynchronousFileChannel(Creating an AsynchronousFileChannel)

AsynchronousFileChannel的創(chuàng)建可以通過open()靜態(tài)方法:

Path path = Paths.get("data/test.xml");

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

open()的第一個參數(shù)是一個Path實體,指向我們需要操作的文件。 第二個參數(shù)是操作類型。上述示例中我們用的是StandardOpenOption.READ,表示以讀的形式操作文件。

讀取數(shù)據(jù)(Reading Data)

讀取AsynchronousFileChannel的數(shù)據(jù)有兩種方式。每種方法都會調用AsynchronousFileChannel的一個read()接口。下面分別看一下這兩種寫法。

通過Future讀取數(shù)據(jù)(Reading Data Via a Future)

第一種方式是調用返回值為Future的read()方法:

Future<Integer> operation = fileChannel.read(buffer, 0);

這種方式中,read()接受一個ByteBuffer座位第一個參數(shù),數(shù)據(jù)會被讀取到ByteBuffer中。第二個參數(shù)是開始讀取數(shù)據(jù)的位置。

read()方法會立刻返回,即使讀操作沒有完成。我們可以通過isDone()方法檢查操作是否完成。

下面是一個略長的示例:

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

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

Future<Integer> 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();

在這個例子中我們創(chuàng)建了一個AsynchronousFileChannel,然后創(chuàng)建一個ByteBuffer作為參數(shù)傳給read。接著我們創(chuàng)建了一個循環(huán)來檢查是否讀取完畢isDone()。這里的循環(huán)操作比較低效,它的意思是我們需要等待讀取動作完成。

一旦讀取完成后,我們就可以把數(shù)據(jù)寫入ByteBuffer,然后輸出。

通過CompletionHandler讀取數(shù)據(jù)(Reading Data Via a CompletionHandler)

另一種方式是調用接收CompletionHandler作為參數(shù)的read()方法。下面是具體的使用:

fileChannel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
    @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) {

    }
});

這里,一旦讀取完成,將會觸發(fā)CompletionHandler的completed()方法,并傳入一個Integer和ByteBuffer。前面的整形表示的是讀取到的字節(jié)數(shù)大小。第二個ByteBuffer也可以換成其他合適的對象方便數(shù)據(jù)寫入。 如果讀取操作失敗了,那么會觸發(fā)failed()方法。

寫數(shù)據(jù)(Writing Data)

和讀數(shù)據(jù)類似某些數(shù)據(jù)也有兩種方式,調動不同的的write()方法,下面分別看介紹這兩種方法。

通過Future寫數(shù)據(jù)(Writing Data Via a Future)

通過AsynchronousFileChannel我們可以一步寫數(shù)據(jù)

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<Integer> operation = fileChannel.write(buffer, position);
buffer.clear();

while(!operation.isDone());

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

首先把文件已寫方式打開,接著創(chuàng)建一個ByteBuffer座位寫入數(shù)據(jù)的目的地。再把數(shù)據(jù)進入ByteBuffer。最后檢查一下是否寫入完成。 需要注意的是,這里的文件必須是已經(jīng)存在的,否者在嘗試write數(shù)據(jù)是會拋出一個java.nio.file.NoSuchFileException.

檢查一個文件是否存在可以通過下面的方法:

if(!Files.exists(path)){
    Files.createFile(path);
}

通過CompletionHandler寫數(shù)據(jù)(Writing Data Via a CompletionHandler)

我們也可以通過CompletionHandler來寫數(shù)據(jù):

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<Integer, ByteBuffer>() {

    @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();
    }
});

同樣當數(shù)據(jù)吸入完成后completed()會被調用,如果失敗了那么failed()會被調用。