AsynchronousFileChannel

java.nio.channels.AsynchronousFileChannel Example

This article introduces the AsynchronousFileChannel class and its basic usage. This class is available since the Java SE 7 as part of Java NIO 2 File API. This article shows reading from and writing to file using asynchronous file channels.

The examples in this article are compiled and run in Windows OS environment. Note that Java SE 7 is required to run the code.
 
 
 
 
 
 

1. Introduction

An asynchronous channel represents a connection that supports non-blocking operations such as connecting, reading, and writing. This also provides mechanisms for controlling and monitoring the I/O operations after they’ve been initiated.

These NIO 2 API’s in Java 7 enhance the New (or Non-blocking) I/O APIs (NIO) introduced in Java 1.4 by adding asynchronous channels to the java.nio.channels package. AsynchronousFileChannel class is one them. This is similar to that of the NIO’s FileChannel, except that this channel enables file operations to execute asynchronously. Here is a link to an example of FileChannel.

In synchronous I/O operation a thread enters into an action and waits until the request is completed. When the same action occurs in asynchronous environment a thread performs the I/O operation, and the thread passes the request to the operating system’s kernel and continues to process another job. The kernel signals the thread when the operation is completed the thread respects the signal and interrupts the current job and processes the I/O job as needed.

Asynchronous channels are safe for use by multiple concurrent threads.

The API provides two mechanisms for monitoring and controlling the initiated asynchronous I/O operations.

The example in this article shows the usage of both mechanisms.

2. Reading and Writing Files using AsynchronousFileChannel

AsynchronousFileChannel abstract class implements AsynchronousChannel interface. This is an asynchronous channel for reading, writing, and manipulating a file. The reading and writing bytes uses buffers as in file channels.

An asynchronous file channel does not have a current position within the file like in synchronous file channels. Instead, the file position is specified to each read and write method that initiates asynchronous operations. Asynchronous file channel has additional methods for locking files, truncating files, and get file size.

The following sections explain two examples using asynchronous file channel to: read a file and write to a file.

3. Reading from a File

This example shows the steps to read a file using an asynchronous file channel into a buffer and print the buffer contents.

3.1. Input file:

The file contains a sequence of bytes that can be read. This is an existing file.

String filePath = "readfile.txt";
Path path = Paths.get(filePath);

3.2. Create a channel:

An AsynchronousFileChannel is created when a file is opened by invoking the open() static method defined by this class. This opens a file for reading or writing, returning an asynchronous file channel to access the file. The resulting channel is associated with default thread pool. java.nio.file.OpenOption specifies how the file is opened (for example, READ or WRITE). The method throws IOException.

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

3.3. Create a buffer:

Create a ByteBuffer using it’s allocate() static method. In this example, the initial capacity is set to 100.

ByteBuffer buffer = ByteBuffer.allocate(100);

3.4. Read from the channel into the buffer:

AsynchronousFileChannel‘s read() method reads a sequence of bytes from this channel into the given buffer, starting at the given file position.

Future result = channel.read(buffer, 0); // position = 0

The read() method returns a Future representing the pending result of the operation. The Future‘s get() method returns the number of bytes read or -1 if the given position is greater than or equal to the file size.

  • About Future:

    Future<V> interface is defined in the java.util.concurrent package. The type parameter V is the result type returned by this Future‘s get() method.
    A Future represents the result of an asynchronous computation. There are methods to check if the computation is complete (isDone()), to wait for its completion and to retrieve the result of the computation (get(longTime, TimeUnit), get()), and to cancel task execution (cancel()).

The following code snippet shows that while the read operation is in progress, the application tracks the progress thru the Future‘s isDone() method. The method returns false until the read completes. The loop allows that some other task can be done while the read is in progress.

while (! result.isDone()) {
			
    System.out.println("Do something else while reading is in progress... ");
}

The following code snippet shows that the operation is completed. The Future‘s isDone() method returns true.

System.out.println("Reading done: " + result.isDone());
System.out.println("Bytes read from file: " + result.get());

The Future‘s get() method returns the number of bytes read from the file into the buffer. The method throws ExecutionException and InterruptedException.

3.5. Print the buffer contents:

The byte buffer has a position() method. Initially this is zero. After the read, the value is 100. The buffer’s flip() method makes the buffer ready for a new sequence of relative get operations: It sets the limit to the current position (in this example, 100) and then sets the position to zero.

buffer.flip();

while (buffer.hasRemaining()) {
				
    System.out.print((char) buffer.get());                
}

3.6. Clear buffer and close:

The buffer’s clear() method makes a buffer ready for a new sequence of channel-read: It sets the limit to the capacity (100) and the position to zero.

buffer.clear();
channel.close();

The channel’s close() method closes this channel. This method throws IOException.

The following is the complete code for the example showing the reading from a file using asynchronous file channel.

ReadExample.java

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

public class ReadExample {

    public static void main (String [] args)
            throws Exception {
	
        new ReadExample().readFile();
    }
	
    private void readFile()
            throws IOException, InterruptedException, ExecutionException {
	
        String filePath = "readfile.txt";
        printFileContents(filePath);
        Path path = Paths.get(filePath);
		
        AsynchronousFileChannel channel =
            AsynchronousFileChannel.open(path, StandardOpenOption.READ);
		
        ByteBuffer buffer = ByteBuffer.allocate(100);

        Future result = channel.read(buffer, 0); // position = 0
			
        while (! result.isDone()) {
			
            System.out.println("Do something else while reading is in progress... ");
        }
		
        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 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();
    }
}

The output is:

File contents:
All the way from the inquisitive solarium on the top floor to the garrulous kitchen in the basement, little groups - convalescents in wheeled chairs, nurses with tardy trays, lean internes on rubber soles, grizzled orderlies trailing damp mops - met to whisper and separated to disseminate the bad news. Doctor Hudson was on the verge of a collapse.
     *
Do something else while reading is in progress...

Reading done: true
Bytes read from file: 100
Buffer contents: All the way from the inquisitive solarium on the top floor to the garrulous kitchen in the basement,

From the output:

  • File contents: … This is the text in the file.
  • The output “Do something else while reading is in progress…” is displayed while the file read is in progress.
  • Reading done: true. The Future’s isDone() method returns true, as the file read is complete.
  • Bytes read from file: 100. The Future’s get() method returns 100, the number of bytes read into the buffer.
  • Buffer contents: All the way from the inquisitive solarium on the top floor to the garrulous kitchen in the basement,. The 100 bytes in the buffer.

4. Writing to a File

This example shows the steps to write to a file through an asynchronous file channel from a buffer source. Then the file contents are printed.

4.1. The input:

The input is a string and is converted to a byte array.

String input = "Content to be written to the file.";
byte [] byteArray = input.getBytes();

4.2. Create a buffer:

The ByteBuffer‘s wrap() static method wraps a byte array into a buffer. The new buffer’s capacity and limit will be array.length of the input byte array and its initial position will be zero. Now, the input contents are in the buffer.

ByteBuffer buffer = ByteBuffer.wrap(byteArray);

4.3. Create a channel:

The AsynchronousFileChannel‘s open() static method opens a file for writing, returning an asynchronous file channel to access the file.

Path path = Paths.get("writefile.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

Note that an empty file must already exist, for this example. The file is opened for WRITE access and bytes will be written to the file. The method throws IOException.

4.4. Create a completion handler:

A handler is created for consuming the result of an asynchronous I/O operation. After a channel’s write method is completed, the handler has functions that are executed.

The handler implements CompletionHandler interface and overrides its two methods. The completed() method is invoked when the I/O operation completes successfully. The failed() method is invoked if the I/O operations fails.

The following code snippet shows the handler’s implementation.

CompletionHandler handler = new CompletionHandler() {
    @Override
    public void completed(Integer result, Object attachment) { 
        System.out.println(attachment + " completed and " + result + " bytes are written."); 
    } 
    @Override
    public void failed(Throwable e, Object attachment) {
        System.out.println(attachment + " failed with exception:");
        e.printStackTrace();
    }
};

4.5. Write the buffer into the channel’s file:

The AsynchronousFileChannel‘s write() method writes a sequence of bytes to this channel’s file from the given buffer.

The write() method takes as parameters:

  • A byte buffer containing the contents to write to the file
  • An absolute start position in the file for writing
  • An attachment object (or null) that is passed on to the completion handler methods
  • A completion handler for consuming the result
channel.write(buffer, 0, "Write operation ALFA", handler);

In this example, the position is zero and the attachment object is the string “Write operation ALFA” are specified for the write() method as shown in the above code snippet.

4.6. Close channel:

channel.close();

The asynchronous file channel’s close() method closes this channel. This method throws IOException.

4.7. Print the file contents:

The file contents are printed to the terminal output.

The following is the complete code for the example showing the writing to a file using asynchronous file channel.

WriteExample.java

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

public class WriteExample {

    public static void main (String [] args)
            throws Exception {
	
        new WriteExample().writeFile();
    }
	
    private 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("writefile.txt");
        AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
			
        CompletionHandler handler = new CompletionHandler() {

          @Override
          public void completed(Integer result, Object attachment) { 
			
            System.out.println(attachment + " completed and " + result + " bytes are written.");
          } 
          @Override
          public void failed(Throwable e, Object attachment) {

            System.out.println(attachment + " failed with exception:");
            e.printStackTrace();
          }
        };
	
        channel.write(buffer, 0, "Write operation ALFA", handler);
	
        channel.close();
	
        printFileContents(path.toString());
    }
    private 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();
    }
}

The output is:

Input string: Content to be written to the file.
Write operation ALFA completed and 34 bytes are written.
File contents: Content to be written to the file.

From the output:

  • Input string: Content to be written to the file. This is the input to the buffer from which it is written to the file.
  • Write operation ALFA completed and 34 bytes are written. This message is printed from the completed() method of the CompletionHandler. This denotes that the asynchronous file write operation is successful.
  • File contents: Content to be written to the file. This is the content from the file written from the source buffer. Note that the contents of the input string and the file are same.

5. Download Java Source Code

This was an example of java.nio.channels.AsynchronousFileChannel.

Download
You can download the full source code of this example here: AsynchronousFileChannelExamples.zip

Prasad Saya

Prasad Saya is a software engineer with over ten years’ experience in application development, maintenance, testing and consulting on various platforms. He is a certified Java and Java EE developer. At present his interest is in developing Java applications. He also has experience working with databases and ERP applications.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button