Java NIO - AsynchronousFileChannel

  • 简述

    众所周知,Java NIO支持并发和多线程,这使我们能够同时处理不同的通道。因此,在 Java NIO 包中负责此情况的 API 是在 NIO 通道包下定义的异步文件通道。因此,异步文件通道的限定名称是 java.nio.channels.AsynchronousFileChannel
    异步文件通道类似于 NIO 的文件通道,不同之处在于此通道使文件操作能够异步执行,这与同步 I/O 操作不同,同步 I/O 操作中线程进入操作并等待请求完成。因此,异步通道对于多个并发线程是安全的。
    在异步中,请求通过线程传递到操作系统的内核以完成它,同时线程继续处理另一个作业。一旦内核的工作完成,它就会向线程发出信号,然后线程会确认信号并中断当前作业并根据需要处理 I/O 作业。
    为了实现并发性,此通道提供了两种方法,其中一种方法是返回 java.util.concurrent.Future 对象,另一种方法是将 java.nio.channels.CompletionHandler对象传递给操作。
    我们将通过示例逐一了解这两种方法。
    • Future 对象 − 在此,Future 接口的实例从通道返回。在 Future 接口中,有 get() 方法返回异步处理的操作状态,在此基础上可以决定其他任务的进一步执行。我们还可以通过调用其isDone方法来检查任务是否已完成。
  • 下面的示例演示如何异步使用 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();
       }
    }
    
  • 输出

    
    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? 
    
    • Completion Handler
      这种方法非常简单,因为在这里我们使用 CompletionHandler 接口并覆盖其两种方法,一个是 completed() 方法,该方法在 I/O 操作成功完成时调用,另一个是 fail() 方法,如果 I/O 操作失败,则调用该方法。在此中,将创建一个处理程序来使用异步 I/O 操作的结果,因为一旦任务完成,则只有处理程序具有执行的函数。
  • 下面的示例演示如何使用完成处理程序异步执行任务。
    
    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();
       }
    }
    
  • 输出

    
    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.