In a synchronous file I/O, the request to the I/O operation waits until the I/O operation is complete.
In an asynchronous file I/O, the request for an I/O operation is performed by the system asynchronously.
When the system finishes the file I/O, it notifies the application about the completion of its request.
java.nio.channels.AsynchronousFileChannel class represents an asynchronous file channel.
The static open() method of the AsynchronousFileChannel class gets an instance of the AsynchronousFileChannel class.
The following code shows how to get an asynchronous file channel for WRITE.
Path path = Paths.get("C:\\Java_Dev\\rainbow.txt");
AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE);
The AsynchronousFileChannel provides two ways to handle the result of an asynchronous file I/O operation.
Each method of the AsynchronousFileChannel class that supports asynchronous file I/O operation has two versions.
One version returns a Future object, which we can use to handle the result of the requested asynchronous operation.
The get() method of the Future object returns the number of bytes written to the file channel.
The following code uses the version of the write() method that returns a Future object:
ByteBuffer dataBuffer = a buffer; long startPosition = 0; Future<Integer> result = afc.write(dataBuffer, startPosition);
Once we get a Future object, we can use a polling method or a blocked waiting method to handle the result of the asynchronous file I/O.
The following code shows the polling method, where it keeps calling the isDone() method of the Future object to check if the I/O operation is finished:
while (!result.isDone()) {
}
int writtenNumberOfBytes = result.get();
Another version of the methods of the AsynchronousFileChannel class gets a CompletionHandler object whose methods are called when the requested asynchronous I/O operation completes or fails.
The CompletionHandler interface has two methods: completed() and failed().
The completed() method is called when the requested I/O operation completes successfully.
When the requested I/O operation fails, the failed() method is called.
The following code uses an object of the Attachment class as an attachment to completion handler:
class Attachment { public Path path; public ByteBuffer buffer; public AsynchronousFileChannel asyncChannel; } class MyHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment attach) { // Handle completion of the I/O operation } @Override public void failed(Throwable e, Attachment attach) { // Handle failure of the I/O operation } }
The following code uses a MyHandler instance as a completion handler for an asynchronous write operation.
MyHandler handler = new MyHandler(); ByteBuffer dataBuffer = get a data buffer; Attachment attach = new Attachment(); attach.asyncChannel = afc; attach.buffer = dataBuffer; attach.path = path; // Perform the asynchronous write operation afc.write(dataBuffer, 0, attach, handler);
The following code demonstrates how to use a CompletionHandler object to handle the results of an asynchronous write to a file.
import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.WRITE; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) throws Exception { Path path = Paths.get("test.txt"); AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE); WriteHandler handler = new WriteHandler(); ByteBuffer dataBuffer = getDataBuffer(); Attachment attach = new Attachment(); attach.asyncChannel = afc; attach.buffer = dataBuffer; attach.path = path; afc.write(dataBuffer, 0, attach, handler); System.out.println("Sleeping for 5 seconds..."); Thread.sleep(5000); } public static ByteBuffer getDataBuffer() { String lineSeparator = System.getProperty("line.separator"); StringBuilder sb = new StringBuilder(); sb.append("test"); sb.append(lineSeparator); sb.append("test"); sb.append(lineSeparator); String str = sb.toString(); Charset cs = Charset.forName("UTF-8"); ByteBuffer bb = ByteBuffer.wrap(str.getBytes(cs)); return bb; } } class Attachment { public Path path; public ByteBuffer buffer; public AsynchronousFileChannel asyncChannel; } class WriteHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment attach) { System.out.format("%s bytes written to %s%n", result, attach.path.toAbsolutePath()); try { attach.asyncChannel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable e, Attachment attach) { try { attach.asyncChannel.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
The following code demonstrates how to use a Future object to handle the results of an asynchronous write to a file.
import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.WRITE; /*from w ww . ja v a 2 s.c om*/ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.Future; public class Main { public static ByteBuffer getDataBuffer() { String lineSeparator = System.getProperty("line.separator"); StringBuilder sb = new StringBuilder(); sb.append("test"); sb.append(lineSeparator); String str = sb.toString(); Charset cs = Charset.forName("UTF-8"); ByteBuffer bb = ByteBuffer.wrap(str.getBytes(cs)); return bb; } public static void main(String[] args) throws Exception { Path path = Paths.get("test.txt"); try (AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE)) { ByteBuffer dataBuffer = getDataBuffer(); Future<Integer> result = afc.write(dataBuffer, 0); while (!result.isDone()) { System.out.println("Sleeping for 2 seconds..."); Thread.sleep(2000); } int writtenBytes = result.get(); System.out.format("%s bytes written to %s%n", writtenBytes, path.toAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } } }
The code above generates the following result.
The following code demonstrates how to use a CompletionHandler object to handle the results of an asynchronous read from a file.
import static java.nio.file.StandardOpenOption.READ; /* w ww .j a v a 2 s. c o m*/ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) throws Exception{ Path path = Paths.get("test.txt"); AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, READ); ReadHandler handler = new ReadHandler(); int fileSize = (int) afc.size(); ByteBuffer dataBuffer = ByteBuffer.allocate(fileSize); Attachment attach = new Attachment(); attach.asyncChannel = afc; attach.buffer = dataBuffer; attach.path = path; afc.read(dataBuffer, 0, attach, handler); System.out.println("Sleeping for 5 seconds..."); Thread.sleep(5000); } } class Attachment { public Path path; public ByteBuffer buffer; public AsynchronousFileChannel asyncChannel; } class ReadHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment attach) { System.out.format("%s bytes read from %s%n", result, attach.path); System.out.format("Read data is:%n"); byte[] byteData = attach.buffer.array(); Charset cs = Charset.forName("UTF-8"); String data = new String(byteData, cs); System.out.println(data); try { // Close the channel attach.asyncChannel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable e, Attachment attach) { System.out.format("Read operation on %s file failed." + "The error is: %s%n", attach.path, e.getMessage()); try { // Close the channel attach.asyncChannel.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
The code above generates the following result.
The following code shows how to use a Future object to handle the results of an asynchronous read from a file. It uses the wait method (a Future.get() method call) to wait for the asynchronous file I/O to complete.
/*w w w .j a v a 2s.c om*/ import static java.nio.file.StandardOpenOption.READ; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public class Main { public static void main(String[] args) throws Exception { Path path = Paths.get("test.txt"); try (AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, READ)) { int fileSize = (int) afc.size(); ByteBuffer dataBuffer = ByteBuffer.allocate(fileSize); Future<Integer> result = afc.read(dataBuffer, 0); int readBytes = result.get(); System.out.format("%s bytes read from %s%n", readBytes, path); System.out.format("Read data is:%n"); byte[] byteData = dataBuffer.array(); Charset cs = Charset.forName("UTF-8"); String data = new String(byteData, cs); System.out.println(data); } catch (IOException ex) { ex.printStackTrace(); } } }
The code above generates the following result.