当前位置: 首页 > 教程 > Java NIO >

Java NIO AsynchronousFileChannel

精华
小牛编辑
102浏览
2023-03-14

在Java 7中,它AsynchronousFileChannel已添加到Java NIO。这样AsynchronousFileChannel 就可以从文件中异步读取数据,或将数据异步写入文件。本教程将说明如何使用AsynchronousFileChannel。

1 创建一个AsynchronousFileChannel

您可以AsynchronousFileChannel通过其静态方法创建一个open()。这是创建一个示例AsynchronousFileChannel:

Path path = Paths.get("data/test.xml");

AsynchronousFileChannel fileChannel =
    AsynchronousFileChannel.open(path, StandardOpenOption.READ);

该open()方法的第一个参数是一个Path实例,该实例指向AsynchronousFileChannel要与之关联的文件。

第二个参数是一个或多个打开的选项,它们指示AsynchronousFileChannel要对基础文件执行哪些操作。在此示例中,我们使用StandardOpenOption.READ 表示将打开文件进行读取。

2 读取数据

您可以通过AsynchronousFileChannel两种方式从读取数据。每种读取数据的read()方法都调用的 方法之一AsynchronousFileChannel。以下各节将介绍这两种读取数据的方法。

3 通过Future读取数据

从中读取数据的第一种方法AsynchronousFileChannel是调用read()返回a的方法Future。这是调用该read()方法的样子:

Future<Integer> operation = fileChannel.read(buffer, 0);

该read()方法的该版本ByteBuffer作为第一个参数。从AsynchronousFileChannel读取的数据将被读取到th​​is中ByteBuffer。第二个参数是文件中要开始读取的字节位置。

read()即使读取操作尚未完成, 该方法也会立即返回。您可以通过调用isDone()方法Future返回的实例的方法 来检查读取操作何时完成read()。

这是一个更长的示例,显示了如何使用此版本的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。

4 通过CompletionHandler读取数据

从中读取数据的第二种方法AsynchronousFileChannel是调用read() 以aCompletionHandler作为参数的方法版本。调用此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从中读取数据的地方。您可以自由选择要附加的对象。

如果读取操作失败,则将调用的failed()方法CompletionHandler。

5 写数据

就像读取一样,您可以通过AsynchronousFileChannel两种方式将数据写入。每种写入数据的write()方法都调用的方法之一AsynchronousFileChannel。以下各节将介绍这两种写入数据的方法。

5 通过Future写入数据

在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);
}

6 通过CompletionHandler写入数据

您也可以AsynchronousFileChannel使用CompletionHandler而不是将数据写入到,以告知您何时写入完成Future。这里是将数据写入到的一个例子 AsynchronousFileChannel具有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();
    }
});

该CompletionHandler的completed()方法将被调用写操作完成时。如果由于某种原因写入失败,failed()则会改为调用该方法。

请注意,如何将ByteBuffer用作附件-传递给 CompletionHandler的方法的对象。