原文鏈接:http://tutorials.jenkov.com/java-nio/asynchronousfilechannel.html
Java7中新增了AsynchronousFileChannel作為nio的一部分。AsynchronousFileChannel使得數(shù)據(jù)可以進行異步讀寫。下面將介紹一下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,表示以讀的形式操作文件。
讀取AsynchronousFileChannel的數(shù)據(jù)有兩種方式。每種方法都會調用AsynchronousFileChannel的一個read()接口。下面分別看一下這兩種寫法。
第一種方式是調用返回值為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ù)的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ù)類似某些數(shù)據(jù)也有兩種方式,調動不同的的write()方法,下面分別看介紹這兩種方法。
通過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ù):
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()會被調用。