AsynchronousFileChannel
在Java7被加入了Java NIO嬉挡。AsynchronousFileChannel
讓我們可以以異步的方式從文件讀取或往文件寫入數(shù)據(jù)。本教程會介紹怎么使用AsynchronousFileChannel
汇恤。
Creating an AsynchronousFileChannel
通過靜態(tài)方法open()
可以創(chuàng)建AsynchronousFileChannel
實例庞钢。這有個例子:
Path path = Paths.get("data/test.xml");
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
open()
方法的第一個參數(shù)是指向該AsynchronousFileChannel
關(guān)聯(lián)的文件的Path
實例。
第二個參數(shù)是一個或多個打開選項因谎,它用來告訴AsynchronousFileChannel
要對底層的文件執(zhí)行什么操作基括。本例中,我們使用了StandardOpenOption.READ
财岔,意味著文件將被打開以供讀取风皿。
Reading Data
您可以通過兩種方式從AsynchronousFileChannel
讀取數(shù)據(jù)。讀取數(shù)據(jù)的每一種方法都調(diào)用AsynchronousFileChannel
的read()
方法之一匠璧。這兩種讀取數(shù)據(jù)的方法將在下面的部分中介紹桐款。
Reading Data Via a Future
第一種從AsynchronousFileChannel
讀取數(shù)據(jù)的方式是調(diào)用其返回值類型為Future
的read()
方法。就像下面這樣:
Future<Integer> operation = fielChannel.read(buffer, 0);
這個版本的read()方法接收一個ByteBuffer
作為第一個參數(shù)夷恍。從AsynchronousFileChannel
讀取的數(shù)據(jù)就會被讀入該ByteBuffer
魔眨。第二個參數(shù)是要開始讀取的文件字節(jié)位置。
該read()
方法會立即返回酿雪,即使讀取操作還未完成遏暴。你可以通過調(diào)用read()
方法返回Future
實例的isDone()
方法來檢查讀取操作是否已經(jīng)完成瘪撇。
這有一個長一點的例子宗收,展示了如何是這個版本的read()
方法:
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
算芯,并同一個為0的位置一起作為參數(shù)傳給了read()
方法袋励。在調(diào)用read()
方法后侥啤,該例一直循環(huán)直到read()
方法返回的Future
對象的isDone(
)返回true
為止。當然茬故,這不是一種有效的CPU使用方式 - 但你總需要以某種方式等待讀取操作完成盖灸。
當讀取操作完成后,數(shù)據(jù)就被讀入了ByteBuffer
磺芭,然后裝入了String
赁炎,然后打印。
Reading Data Via a CompletionHandler
從AsynchronousFileChannel
讀取數(shù)據(jù)的第二種方式是調(diào)用其接收一個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) {
}
});
當讀取操作完成后徙垫,CompletionHandler
的completed()
方法就會被調(diào)用讥裤。當傳遞給complete()
方法的參數(shù)時,將傳遞一個整數(shù)姻报,表示讀取了多少字節(jié)己英,以及傳遞給read()
方法的附件。附件是read()
方法的第三個參數(shù)吴旋。本例中就是數(shù)據(jù)被讀入的ByteBuffer
损肛。你可以選擇附帶任何對象。
如果讀取操作失敗荣瑟,則CompletionHandle
r的failed()
會被調(diào)用治拿。
Writing Data
就像讀取數(shù)據(jù)一樣,你有兩種方式可以將數(shù)據(jù)寫入AsynchronousFileChannel
笆焰。寫入數(shù)據(jù)的每一種方法都調(diào)用AsynchronousFileChannel
的write()
方法之一劫谅。這兩種寫數(shù)據(jù)的方法將在下面的部分中介紹。
Writing Data Via a Future
AsynchronousFileChannel
同樣允許你以異步的方式寫入數(shù)據(jù)嚷掠。下面是一個完整的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");
首先捏检,以寫模式打開了一個AsynchronousFileChannel
。然后創(chuàng)建了一個ByteBuffer
叠国,并向其中寫入了一些數(shù)據(jù)未檩。然后ByteBuffer
中的數(shù)據(jù)被寫入了文件。最后粟焊,例子通過檢查返回的Future
來看寫入操作是否完成冤狡。
注意,在代碼工作之前项棠,文件必須已經(jīng)存在悲雳。如果文件不存在,write()
方法會拋出一個java.nio.file.NoSuchFileException
香追。
你可以通過以下代碼來確保Path指向的文件存在:
if (!Files.exists(path)) {
Files.createFile(path);
}
Writing Data Via a CompletionHandler
你也可以用CompletionHandler
代替Future
來向AsynchronousFileChannel
寫入數(shù)據(jù)合瓢,以便在數(shù)據(jù)寫入完成時告知你。下面是一個通過CompletionHandler
向AsynchronousFileChannel
寫入數(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();
}
});
當寫入操作完成后透典,CompletionHandler
的completed()
方法就會被調(diào)用晴楔。如果因為某些原因?qū)е聦懭胧。?code>failed()方法就會被調(diào)用峭咒。
注意ByteBuffer
是怎么作為附件使用的 - 傳給CompletionHandler
的方法的參數(shù)税弃。
發(fā)現(xiàn)貌似有人在看這個系列文章了,有必要說明下凑队,這個Java NIO系列來源于jenkov.com则果,本文只是翻譯,希望大家千萬不要誤會,本文不是原創(chuàng)西壮。原文地址:Java NIO遗增。