NIO详解(十二):AsynchronousFileChannel详解

左手的ㄟ右手 2022-01-29 02:43 856阅读 0赞

1. 概述

Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。FileChannel无法设置为非阻塞模式,他总是运行在阻塞模式下。在Java 7中,AsynchronousFileChannel被添加到Java NIO。AsynchronousFileChannel使读取数据,并异步地将数据写入文件成为可能。

2. 创建一个AsynchronousFileChannel

使用AsynchronousFileChannel提供的静态方法 open() 创建它。示例代码如下:

  1. Path path = Paths.get("data/test.xml");
  2. AsynchronousFileChannel fileChannel =AsynchronousFileChannel.open(path, StandardOpenOption.READ);

第一个参数是一个 PATH 的对象实例,它指向了那个与 AsynchronousFileChannel 相关联的文件。

第二个参数是一个或多个操作选项,它决定了 AsynchronousFileChannel 将对目标文件做何种操作。示例代码中我们使用了 StandardOpenOption.READ ,它表明我们将要对目标文件进行读操作。

3. 从AsynchronousFileChannel中读取数据

3.1 使用Futrue读取数据

从AsynchronousFileChannel读取数据的第一种方法是调用返回Future的read()方法。下面是如何调用这个read()方法的示例:

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

read()方法的这个版本将ByteBuffer作为第一个参数。从AsynchronousFileChannel读取的数据被读入这个ByteBuffer。第二个参数是文件中的字节位置,以便开始读取。

read()方法会立即返回,即使读操作还没有完成。通过调用read()方法返回的Future实例的isDone()方法,您可以检查读取操作是否完成。

  1. AsynchronousFileChannel fileChannel =
  2. AsynchronousFileChannel.open(path, StandardOpenOption.READ);
  3. ByteBuffer buffer = ByteBuffer.allocate(1024);
  4. long position = 0;
  5. Future<Integer> operation = fileChannel.read(buffer, position);
  6. while(!operation.isDone());
  7. buffer.flip();
  8. byte[] data = new byte[buffer.limit()];
  9. buffer.get(data);
  10. System.out.println(new String(data));
  11. buffer.clear();

上面的程序首先创建了一个 AsynchronousFileChannel 对象,然后调用它的read()方法返回一个Future。其中read()方法需要两个参数,一个是ByteBuffer,另一个是读取文件的开始位置。然后通过循环调用isDone() 方法检测读取过程是否完成,完成后 isDone()方法将返回true。尽管这样让cpu空转了一会,但是我们还是应该等读取操作完成后再进行后续的步骤。

一旦读取完成,数据被存储到ByteBuffer,然后将数据转化为字符串既而输出。

3.2 使用CompletionHandler读取数据

第二种读取数据的方式是调用AsynchronousFileChannel 的另一个重载 read() 方法,改方法需要一个CompletionHandler 作为参数。下面是代码示例:

  1. fileChannel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
  2. @Override
  3. public void completed(Integer result, ByteBuffer attachment) {
  4. System.out.println("result = " + result);
  5. attachment.flip();
  6. byte[] data = new byte[attachment.limit()];
  7. attachment.get(data);
  8. System.out.println(new String(data));
  9. attachment.clear();
  10. }
  11. @Override
  12. public void failed(Throwable exc, ByteBuffer attachment) {
  13. }
  14. });

一旦读取操作完成,CompletionHandler的 complete() 方法将会被调用。它的第一个参数是个 Integer类型,表示读取的字节数。第二个参数 attachment 是 ByteBuffer 类型的,用来存储读取的数据。它其实就是由 read() 方法的第三个参数。当前示例中,我们选用 ByteBuffer 来存储数据,其实我们也可以选用其他的类型。读取失败的时候,CompletionHandler的 failed()方法会被调用。

4. 向AsynchronousFileChannel中写入数据

就像读取一样,我们同样有两种方式向 AsynchronousFileChannel 写入数据。我们可以调用它的2个重载的 write() 方法。下面我们将分别加以介绍。

4.1 使用Future读取数据

AsynchronousFileChannel也可以异步写入数据。下面是一个完整的写入示例:

  1. Path path = Paths.get("data/test-write.txt");
  2. AsynchronousFileChannel fileChannel =
  3. AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
  4. ByteBuffer buffer = ByteBuffer.allocate(1024);
  5. long position = 0;
  6. buffer.put("test data".getBytes());
  7. buffer.flip();
  8. Future<Integer> operation = fileChannel.write(buffer, position);
  9. buffer.clear();
  10. while(!operation.isDone());
  11. System.out.println("Write done");

首先实例化一个写入模式的 AsynchronousFileChannel, 然后创建一个 ByteBuffer 并写入一些数据。再然后将数据写入文件。最后,检查返回的 Future,看是否写入完成。

注意,写入目标文件要提前创建好,如果它不存在的话,writh() 方法会抛出一个 java.nio.file.NoSuchFileException。

4.2 使用CompletionHandler写入数据

使用 CompletionHandler代替Future向AsynchronousFileChannel写入数据,这种方式可以更加直接的知道写入过程是否完成。下面是示例程序:

  1. Path path = Paths.get("data/test-write.txt");
  2. if(!Files.exists(path)){
  3. Files.createFile(path);
  4. }
  5. AsynchronousFileChannel fileChannel =
  6. AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
  7. ByteBuffer buffer = ByteBuffer.allocate(1024);
  8. long position = 0;
  9. buffer.put("test data".getBytes());
  10. buffer.flip();
  11. fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
  12. @Override
  13. public void completed(Integer result, ByteBuffer attachment) {
  14. System.out.println("bytes written: " + result);
  15. }
  16. @Override
  17. public void failed(Throwable exc, ByteBuffer attachment) {
  18. System.out.println("Write failed");
  19. exc.printStackTrace();
  20. }
  21. });

当写入程序完成时,CompletionHandler的completed()方法将会被调用,相反的如果写入失败则会调用failed()方法。

发表评论

表情:
评论列表 (有 0 条评论,856人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JAVA NIO详解

    1. IO 和 NIO 相关的预备知识 1.1 IO 的含义 讲 NIO 之前,我们先来看一下 IO。 Java IO 即 Java 输入输出。在开发应用软件时,

    相关 NIO详解(五):Buffer详解

    1. 概述 Java NIO中的Buffer用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。缓冲区本质上是一块可以写入数据,然后可以从