在Java 7中NIO部分新增了AsynchronousFileChannel。AsynchronousFileChannel可以异步的读写文件了。下面教程介绍了它的用法。
创建一个AsynchronousFileChannel
通过它的静态方法open可以创建一个对象:
Path path = Paths.get("data/test.xml");
AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(path, StandardOpenOption.READ);
第一个参数是一个文件路径,它指向要访问的文件。
第二个参数是一个或多个打开的操作选项,它告诉AsynchronousFileChannel在底层对文件执行什么操作。上面的例子我们使用了StandardOpenOption.READ,这就表示文件打开是为了读取数据。
读数据
有两种方法。每种读取数据的方法都调用了AsynchronousFileChannel的read()方法之一。这两种读取数据的方法将在下面几节中讨论。
通过Future读数据
第一种是通过返回一个Future对象来读数据:
Future<Integer> operation = fileChannel.read(buffer, 0);
第一个参数是一个buffer,AsynchronousFileChannel会把数据读到buffer中。第二个参数是文件读取的开始位置。
即使读取操作还没完成,read方法也会立刻返回。你可以通过调用Future对象的isDone()方法来判断,future对象是否处理完成了。下面的例子有点长:
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对象,然后创建了一个buffer传给read方法。在调用read之后,进入while循环,直到isDone方法返回。当然这个例子在CPU利用率上并不高效,但是你需要等待read操作完成。
一旦read操作完成,数据就完全读到了buffer中随即输出到控制台。
通过CompletionHandler读数据
第二种是调用read的另一个版本方法,传入一个CompletionHandler对象,就像这样:
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) {
}
});
一旦read操作完成了,就会回调CompletionHandler的complete方法。complete方法的第一个int表示读到了多少数据。
通过Future写数据
AsynchronousFileChannel也可以异步写数据,下面是一个完整的例子:
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");
通过CompletionHandler写数据
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();
}
});
注意ByteBuffer是如何作为附件使用的——它是传递给CompletionHandler方法的对象。
来源:CSDN
作者:nickDaDa
链接:https://blog.csdn.net/nickDaDa/article/details/103875744