在同步文件I/O中,對I/O操作的請求將等待,直到I/O操作完成。
在異步文件I/O中,I/O操作的請求由系統(tǒng)異步執(zhí)行。
當(dāng)系統(tǒng)完成文件I/O時,它通知應(yīng)用程序其請求的完成。
java.nio.channels.AsynchronousFileChannel類表示異步文件通道。
AsynchronousFileChannel類的靜態(tài)open()方法獲取AsynchronousFileChannel類的實例。
以下代碼顯示了如何獲取WRITE的異步文件通道。
Path path = Paths.get("C:\\Java_Dev\\rainbow.txt"); AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE);
AsynchronousFileChannel提供了兩種方法來處理異步文件I/O操作的結(jié)果。
支持異步文件I/O操作的AsynchronousFileChannel類的每個方法有兩個版本。
一個版本返回一個Future對象,我們可以使用它來處理所請求的異步操作的結(jié)果。
Future對象的get()方法返回寫入文件通道的字節(jié)數(shù)。
以下代碼使用返回Future對象的write()方法的版本:
ByteBuffer dataBuffer = a buffer; long startPosition = 0; Future<Integer> result = afc.write(dataBuffer, startPosition);
一旦我們得到一個Future對象,我們可以使用輪詢方法或阻塞等待方法來處理異步文件I/O的結(jié)果。
下面的代碼顯示了輪詢方法,它將繼續(xù)調(diào)用Future對象的isDone()方法,以檢查I/O操作是否完成:
while (!result.isDone()) { } int writtenNumberOfBytes = result.get();
AsynchronousFileChannel類的另一個版本的方法獲得一個CompletionHandler對象,當(dāng)請求的異步I/O操作完成或失敗時,該對象的方法被調(diào)用。
CompletionHandler接口有兩個方法:completed()和failed()。
當(dāng)所請求的I/O操作成功完成時,將調(diào)用completed()方法。
當(dāng)請求的I/O操作時失敗,則調(diào)用failed()方法。
以下代碼使用Attachment類的對象作為完成處理程序的附件:
class Attachment { public Path path; public ByteBuffer buffer; public AsynchronousFileChannel asyncChannel; } class MyHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment attach) { // Handle completion of the I/O operation } @Override public void failed(Throwable e, Attachment attach) { // Handle failure of the I/O operation } }
以下代碼使用MyHandler實例作為異步寫操作的完成處理程序。
MyHandler handler = new MyHandler(); ByteBuffer dataBuffer = get a data buffer; Attachment attach = new Attachment(); attach.asyncChannel = afc; attach.buffer = dataBuffer; attach.path = path; // Perform the asynchronous write operation afc.write(dataBuffer, 0, attach, handler);
以下代碼演示了如何使用CompletionHandler對象來處理對文件的異步寫入的結(jié)果。
import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.WRITE; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) throws Exception { Path path = Paths.get("test.txt"); AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE); WriteHandler handler = new WriteHandler(); ByteBuffer dataBuffer = getDataBuffer(); Attachment attach = new Attachment(); attach.asyncChannel = afc; attach.buffer = dataBuffer; attach.path = path; afc.write(dataBuffer, 0, attach, handler); System.out.println("Sleeping for 5 seconds..."); Thread.sleep(5000); } public static ByteBuffer getDataBuffer() { String lineSeparator = System.getProperty("line.separator"); StringBuilder sb = new StringBuilder(); sb.append("test"); sb.append(lineSeparator); sb.append("test"); sb.append(lineSeparator); String str = sb.toString(); Charset cs = Charset.forName("UTF-8"); ByteBuffer bb = ByteBuffer.wrap(str.getBytes(cs)); return bb; } } class Attachment { public Path path; public ByteBuffer buffer; public AsynchronousFileChannel asyncChannel; } class WriteHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment attach) { System.out.format("%s bytes written to %s%n", result, attach.path.toAbsolutePath()); try { attach.asyncChannel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable e, Attachment attach) { try { attach.asyncChannel.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
以下代碼演示了如何使用Future對象來處理對文件的異步寫入的結(jié)果。
import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.WRITE; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.Future; public class Main { public static ByteBuffer getDataBuffer() { String lineSeparator = System.getProperty("line.separator"); StringBuilder sb = new StringBuilder(); sb.append("test"); sb.append(lineSeparator); String str = sb.toString(); Charset cs = Charset.forName("UTF-8"); ByteBuffer bb = ByteBuffer.wrap(str.getBytes(cs)); return bb; } public static void main(String[] args) throws Exception { Path path = Paths.get("test.txt"); try (AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE)) { ByteBuffer dataBuffer = getDataBuffer(); Future<Integer> result = afc.write(dataBuffer, 0); while (!result.isDone()) { System.out.println("Sleeping for 2 seconds..."); Thread.sleep(2000); } int writtenBytes = result.get(); System.out.format("%s bytes written to %s%n", writtenBytes, path.toAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } } }
上面的代碼生成以下結(jié)果。
以下代碼演示了如何使用CompletionHandler對象來處理從文件進行異步讀取的結(jié)果。
import static java.nio.file.StandardOpenOption.READ; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) throws Exception{ Path path = Paths.get("test.txt"); AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, READ); ReadHandler handler = new ReadHandler(); int fileSize = (int) afc.size(); ByteBuffer dataBuffer = ByteBuffer.allocate(fileSize); Attachment attach = new Attachment(); attach.asyncChannel = afc; attach.buffer = dataBuffer; attach.path = path; afc.read(dataBuffer, 0, attach, handler); System.out.println("Sleeping for 5 seconds..."); Thread.sleep(5000); } } class Attachment { public Path path; public ByteBuffer buffer; public AsynchronousFileChannel asyncChannel; } class ReadHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment attach) { System.out.format("%s bytes read from %s%n", result, attach.path); System.out.format("Read data is:%n"); byte[] byteData = attach.buffer.array(); Charset cs = Charset.forName("UTF-8"); String data = new String(byteData, cs); System.out.println(data); try { // Close the channel attach.asyncChannel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable e, Attachment attach) { System.out.format("Read operation on %s file failed." + "The error is: %s%n", attach.path, e.getMessage()); try { // Close the channel attach.asyncChannel.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
上面的代碼生成以下結(jié)果。
以下代碼顯示了如何使用Future對象來處理從文件進行異步讀取的結(jié)果。它使用等待方法(Future.get()方法調(diào)用)等待異步文件I/O完成。
import static java.nio.file.StandardOpenOption.READ; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public class Main { public static void main(String[] args) throws Exception { Path path = Paths.get("test.txt"); try (AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, READ)) { int fileSize = (int) afc.size(); ByteBuffer dataBuffer = ByteBuffer.allocate(fileSize); Future<Integer> result = afc.read(dataBuffer, 0); int readBytes = result.get(); System.out.format("%s bytes read from %s%n", readBytes, path); System.out.format("Read data is:%n"); byte[] byteData = dataBuffer.array(); Charset cs = Charset.forName("UTF-8"); String data = new String(byteData, cs); System.out.println(data); } catch (IOException ex) { ex.printStackTrace(); } } }
上面的代碼生成以下結(jié)果。
更多建議: