Java Nio 简明教程

Java NIO - AsynchronousFileChannel

众所周知,Java NIO 支持并发和多线程,这允许我们在同一时间同时处理不同的通道。因此,在 Java NIO 包中负责此操作的 API 是 AsynchronousFileChannel,它在 NIO 通道包下定义。因此 AsynchronousFileChannel 的限定名称为 java.nio.channels.AsynchronousFileChannel

AsynchronousFileChannel 类似于 NIO 的 FileChannel,但不同的是,此通道允许文件操作异步执行,而不像同步 I/O 操作中线程会进入操作并等待请求完成。因此,异步通道可供多个并发线程安全使用。

在异步中,请求由线程传递给操作系统的内核以完成,而线程继续处理另一项工作。一旦内核完成工作,它就会向线程发出信号,然后线程确认信号并中断当前工作并根据需要处理 I/O 工作。

为了实现并发,此通道提供了两种方法,其中一种是返回 java.util.concurrent.Future object ,另一种是将 java.nio.channels.CompletionHandler 类型对象传递给操作。

我们将逐一借助示例了解这两种方法。

  1. Future Object − 在此方法中,一个 Future 接口的实例会从通道返回。在 Future 接口中,有 get() 方法,用于返回基于此方法异步处理的操作的状态,进而可以决定其他任务的进一步执行。我们还可以通过调用其 isDone 方法来检查任务是否已完成。

Example

以下示例显示如何使用 Future 对象和异步任务。

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class FutureObject {
   public static void main(String[] args) throws Exception {
      readFile();
   }
   private static void readFile() throws IOException, InterruptedException, ExecutionException {
      String filePath = "D:fileCopy.txt";
      printFileContents(filePath);
      Path path = Paths.get(filePath);
      AsynchronousFileChannel channel =AsynchronousFileChannel.open(path, StandardOpenOption.READ);
      ByteBuffer buffer = ByteBuffer.allocate(400);
      Future<Integer> result = channel.read(buffer, 0); // position = 0
      while (! result.isDone()) {
         System.out.println("Task of reading file is in progress asynchronously.");
      }
      System.out.println("Reading done: " + result.isDone());
      System.out.println("Bytes read from file: " + result.get());
      buffer.flip();
      System.out.print("Buffer contents: ");
      while (buffer.hasRemaining()) {
         System.out.print((char) buffer.get());
      }
      System.out.println(" ");
      buffer.clear();
      channel.close();
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
   fr.close();
   br.close();
   }
}

Output

File contents:
   To be or not to be?
   Task of reading file is in progress asynchronously.
   Task of reading file is in progress asynchronously.
   Reading done: true
   Bytes read from file: 19
   Buffer contents: To be or not to be?
  1. Completion Handler − 此方法非常简单,就像我们使用 CompletionHandler 接口并覆盖其两个方法一样,一个方法为 completed() ,当 I/O 操作成功完成时调用此方法,另一个方法为 failed() ,当 I/O 操作失败时调用此方法。在这种情况下,会创建一个处理程序来使用异步 I/O 操作的结果,因为只有在任务完成后才执行处理程序的功能。

Example

以下示例显示如何使用 CompletionHandler 进行异步任务。

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class CompletionHandlerDemo {
   public static void main (String [] args) throws Exception {
      writeFile();
   }
   private static void writeFile() throws IOException {
      String input = "Content to be written to the file.";
      System.out.println("Input string: " + input);
      byte [] byteArray = input.getBytes();
      ByteBuffer buffer = ByteBuffer.wrap(byteArray);
      Path path = Paths.get("D:fileCopy.txt");
      AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
      CompletionHandler handler = new CompletionHandler() {
         @Override
         public void completed(Object result, Object attachment) {
            System.out.println(attachment + " completed and " + result + " bytes are written.");
         }
         @Override
         public void failed(Throwable exc, Object attachment) {
            System.out.println(attachment + " failed with exception:");
            exc.printStackTrace();
         }
      };
      channel.write(buffer, 0, "Async Task", handler);
      channel.close();
      printFileContents(path.toString());
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
      fr.close();
      br.close();
   }
}

Output

Input string: Content to be written to the file.
Async Task completed and 34 bytes are written.
File contents:
Content to be written to the file.