1. 概述
本文将深入探讨 Java 7 中 NIO2 的核心增强特性之一:异步文件通道 API。如果你对异步通道 API 还不熟悉,建议先阅读本站的基础教程(点击这里)。此外,理解 NIO.2 的文件操作和路径操作会帮助你更好地掌握本文内容。
要使用 NIO2 的异步文件通道,需导入 java.nio.channels
包:
import java.nio.channels.*;
2. AsynchronousFileChannel 类
本节介绍执行文件异步操作的核心类 AsynchronousFileChannel
。创建实例需调用静态 open
方法:
Path filePath = Paths.get("/path/to/file");
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
filePath, READ, WRITE, CREATE, DELETE_ON_CLOSE);
所有枚举值来自 StandardOpenOption
。open
方法的参数说明:
- 第一个参数:
Path
对象,表示文件位置 - 后续参数:文件通道的可用选项集合
✅ 支持的常用操作:
- 读写文件
- 创建文件
- 关闭时自动删除
❌ 注意:若只需部分操作,可指定对应选项。例如只读文件:
Path filePath = Paths.get("/path/to/file");
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
filePath, StandardOpenOption.READ);
3. 读取文件内容
NIO2 提供两种异步读取方式:Future
和 CompletionHandler
。假设测试资源目录下存在 file.txt
,内容为 baeldung.com
。
3.1. Future 方式
使用 Future
实现异步读取:
@Test
public void givenFilePath_whenReadsContentWithFuture_thenCorrect() {
Path path = Paths.get(
URI.create(
this.getClass().getResource("/file.txt").toString()));
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> operation = fileChannel.read(buffer, 0);
// 执行其他代码,读取操作在后台进行
operation.get();
String fileContent = new String(buffer.array()).trim();
buffer.clear();
assertEquals(fileContent, "baeldung.com");
}
关键点解析:
read
方法参数:ByteBuffer
:存储读取内容long
:文件起始读取位置(0 表示开头)
read
立即返回,不阻塞线程operation.get()
阻塞直到操作完成- ⚠️ 修改位置参数会影响结果:如设为 7,将读取
g.com
(第 7 个字符是 'g')
3.2. CompletionHandler 方式
使用回调机制处理读取结果:
@Test
public void
givenPath_whenReadsContentWithCompletionHandler_thenCorrect() {
Path path = Paths.get(
URI.create( this.getClass().getResource("/file.txt").toString()));
AsynchronousFileChannel fileChannel
= AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
fileChannel.read(
buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
// result: 读取的字节数
// attachment: 包含内容的缓冲区
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
});
}
核心机制:
- 第三个参数是
CompletionHandler
实例 - 泛型参数:
Integer
:操作返回类型(字节数)ByteBuffer
:附加对象类型(这里传递缓冲区)
- 操作完成后自动调用
completed
方法 - ⚠️ 此示例无法直接断言,仅作演示用
4. 写入文件内容
NIO2 同样支持异步写入,同样提供 Future
和 CompletionHandler
两种方式。
4.1. 特殊注意事项
创建写入通道时的关键选项:
AsynchronousFileChannel fileChannel
= AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
✅ 常用选项组合:
CREATE
:文件不存在时自动创建APPEND
:追加内容而非覆盖DELETE_ON_CLOSE
:关闭时删除文件(测试场景推荐)
测试用通道创建示例:
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
path, WRITE, CREATE, DELETE_ON_CLOSE);
为避免重复代码,封装读取方法:
public static String readContent(Path file) {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
file, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> operation = fileChannel.read(buffer, 0);
// 执行其他代码,读取操作在后台进行
operation.get();
String fileContent = new String(buffer.array()).trim();
buffer.clear();
return fileContent;
}
4.2. Future 方式
使用 Future
异步写入:
@Test
public void
givenPathAndContent_whenWritesToFileWithFuture_thenCorrect() {
String fileName = UUID.randomUUID().toString();
Path path = Paths.get(fileName);
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
path, WRITE, CREATE, DELETE_ON_CLOSE);
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("hello world".getBytes());
buffer.flip();
Future<Integer> operation = fileChannel.write(buffer, 0);
buffer.clear();
// 执行其他代码,写入操作在后台进行
operation.get();
String content = readContent(path);
assertEquals("hello world", content);
}
执行流程:
- 生成随机文件名
- 创建带自动清理的文件通道
- 准备缓冲区数据(注意
flip()
切换读写模式) - 异步写入后通过
get()
等待完成 - 验证写入内容
4.3. CompletionHandler 方式
使用回调机制处理写入结果:
@Test
public void
givenPathAndContent_whenWritesToFileWithHandler_thenCorrect() {
String fileName = UUID.randomUUID().toString();
Path path = Paths.get(fileName);
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
path, WRITE, CREATE, DELETE_ON_CLOSE);
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("hello world".getBytes());
buffer.flip();
fileChannel.write(
buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
// result: 写入的字节数
// attachment: 使用的缓冲区
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
});
}
核心差异:
- 第三个参数传递
CompletionHandler
实例 - 写入完成后自动触发
completed
回调 - 无需手动阻塞等待操作完成
5. 总结
本文系统介绍了 Java NIO2 中异步文件通道的核心特性:
- ✅ 两种异步操作模式:
Future
和CompletionHandler
- ✅ 灵活的文件操作选项(读/写/创建/删除)
- ✅ 高效的非阻塞 I/O 处理
完整代码示例可访问 GitHub 项目。实际开发中,根据场景选择合适的方式:
- 需要精确控制时用
Future
- 需要事件驱动时用
CompletionHandler