在同步檔案I/O
中,對I/O
操作的請求將等待,直到I/O
操作完成。在非同步檔案I/O
中,I/O
操作的請求由系統非同步執行。當系統完成檔案I/O
時,它通知應用程式其請求的完成。
java.nio.channels.AsynchronousFileChannel
類表示非同步檔案通道。使用AsynchronousFileChannel
類的靜態open()
方法獲取AsynchronousFileChannel
類的範例。
以下程式碼顯示了如何獲取WRITE
的非同步檔案通道。
Path path = Paths.get("C:\\Java_Dev\\rainbow.txt");
AsynchronousFileChannel afc = AsynchronousFileChannel.open(path, WRITE, CREATE);
AsynchronousFileChannel
提供了兩種方法來處理非同步檔案I/O
操作的結果。
java.util.concurrent.Future
物件。java.nio.channels.CompletionHandler
物件。支援非同步檔案I/O
操作的AsynchronousFileChannel
類的每個方法有兩個版本。一個版本返回一個Future
物件,可以使用它來處理所請求的非同步操作的結果。
Future
物件的get()
方法返回寫入檔案通道的位元組數。以下程式碼使用返回Future
物件的write()
方法的版本:
ByteBuffer dataBuffer = a buffer;
long startPosition = 0;
Future<Integer> result = afc.write(dataBuffer, startPosition);
當得到一個Future
物件後,可以使用輪詢方法或阻塞等待方法來處理非同步檔案I/O
的結果。
下面的程式碼顯示了輪詢方法,它將繼續呼叫Future
物件的isDone()
方法來檢查I/O
操作是否完成:
while (!result.isDone()) {
}
int writtenNumberOfBytes = result.get();
AsynchronousFileChannel
類的另一個版本的方法獲得一個CompletionHandler
物件,當請求的非同步I/O
操作完成或失敗時,該物件的方法被呼叫。
CompletionHandler
介面有兩個方法:completed()
和failed()
。當所請求的I/O
操作成功完成時,將呼叫completed()
方法。當請求的I/O
操作失敗時,將呼叫failed()
方法。
以下程式碼使用Attachment
類的物件作為完成處理程式的附件:
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
}
}
以下程式碼使用MyHandler
範例作為非同步寫操作的完成處理程式。
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);
以下程式碼演示了如何使用CompletionHandler
物件來處理對檔案的非同步寫入的結果。
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();
}
}
}
以下程式碼演示了如何使用Future
物件來處理對檔案的非同步寫入的結果。
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.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();
}
}
}
上面的程式碼生成以下結果。
Sleeping for 2 seconds...
6 bytes written to F:\website\yiibai\worksp\test.txt
以下程式碼演示了如何使用CompletionHandler
物件來處理從檔案進行非同步讀取的結果。
import static java.nio.file.StandardOpenOption.READ;
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();
}
}
}
上面的程式碼生成以下結果。
Sleeping for 5 seconds...
13 bytes read from test.txt
Read data is:
test
test2
以下程式碼顯示了如何使用Future
物件來處理從檔案進行非同步讀取的結果。它使用等待方法(Future.get()
方法呼叫)等待非同步檔案I/O
完成。
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();
}
}
}
上面的程式碼生成以下結果。
13 bytes read from test.txt
Read data is:
test
test2