Java NIO AsynchronousFileChannel
在Java 7中," AsynchronousFileChannel"已添加到Java NIO。 AsynchronousFileChannel
使得异步读取数据和向文件写入数据成为可能。本教程将说明如何使用AsynchronousFileChannel
。
创建一个AsynchronousFileChannel
我们可以通过静态方法open()创建一个AsynchronousFileChannel。这是创建AsynchronousFileChannel
的示例:
Path path = Paths.get("data/test.xml"); AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
open()方法的第一个参数是一个Path实例,该实例指向与AsynchronousFileChannel关联的文件。
第二个参数是一个或者多个打开的选项,它们告诉" AsynchronousFileChannel"要在基础文件上执行哪些操作。在此示例中,我们使用了" StandardOpenOption.READ",这意味着将打开文件进行读取。
读取数据
我们可以通过两种方式从" AsynchronousFileChannel"中读取数据。每种读取数据的方法都调用" AsynchronousFileChannel"的" read()"方法之一。以下各节将介绍这两种读取数据的方法。
通过未来读取数据
从" AsynchronousFileChannel"读取数据的第一种方法是调用" read()"方法,该方法返回" Future"。这是调用read()
方法的样子:
Future<Integer> operation = fileChannel.read(buffer, 0);
这个版本的read()方法将ByteBuffer作为第一个参数。从" AsynchronousFileChannel"读取的数据被读入" ByteBuffer"。第二个参数是文件中要开始读取的字节位置。
即使读取操作尚未完成," read()"方法也会立即返回。我们可以通过调用read()方法返回的Future实例的isDone()方法来检查读取操作何时完成。
这是一个更长的示例,显示了如何使用此版本的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();
本示例创建一个" AsynchronousFileChannel",然后创建一个" ByteBuffer",将其作为参数传递给" read()"方法,并将其位置设为0。在调用" read()"之后,该示例循环运行,直到" isDone( )返回的" Future"的方法返回true。当然,这不是对CPU的非常有效的使用,但是我们需要以某种方式等待读取操作完成。
一旦读取操作完成,数据将被读入到" ByteBuffer"中,然后被读入一个String中,并被打印到" System.out"中。
通过CompletionHandler读取数据
从" AsynchronousFileChannel"读取数据的第二种方法是调用以" CompletionHandler"作为参数的" read()"方法版本。这是我们如何调用此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()
方法将被调用。作为" completed()"方法的参数,将传递" Integer"(告诉读取了多少字节),并将"附件"传递给" read()"方法。 "附件"是read()方法的第三个参数。在这种情况下,也就是" ByteBuffer",数据也被读入其中。我们可以自由选择要添加的对象。
如果读取操作失败,则将改为调用CompletionHandler的failed()方法。
写数据
就像读取一样,我们可以通过两种方式将数据写入" AsynchronousFileChannel"。每种写数据的方法都调用" AsynchronousFileChannel"的" write()"方法之一。以下各节将介绍这两种写入数据的方法。
通过未来写入数据
AsynchronousFileChannel
也使我们能够异步写入数据。这是完整的JavaAsynchronousFileChannel
编写示例:
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"。然后创建一个" ByteBuffer"并将一些数据写入其中。然后,将" ByteBuffer"中的数据写入文件。最后,该示例检查返回的Future
以查看写操作何时完成。
请注意,此代码生效之前,该文件必须已经存在。如果文件不存在,则write()方法将抛出java.nio.file.NoSuchFileException`。
我们可以使用以下代码确保Path
指向的文件存在:
if(!Files.exists(path)){ Files.createFile(path); }
通过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<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()方法。如果由于某种原因写入失败,则会调用failed()
方法。
注意," ByteBuffer"如何用作对象的附件,该对象传递给" CompletionHandler"的方法。