1. 简介
在 Java 中复制目录(包含所有文件和子目录)是一个常见但容易踩坑的操作。实现方式主要有三种:使用 JDK 自带的 NIO API、传统的 IO 流 + 递归,或者借助第三方工具类库如 Apache Commons IO。
本文将逐一演示这些方法,帮你选出最适合当前项目的方案。✅
2. 使用 java.nio API(推荐)
从 Java 7 开始,java.nio.file
包(也就是常说的 NIO.2)大大简化了文件操作。它提供了 Files
、Paths
和 Path
等核心类,让目录遍历和复制变得简单粗暴。
核心思路:
- 使用
Files.walk()
遍历源目录下的所有路径(包括子目录和文件) - 对每个路径,计算其相对于源目录的相对路径,拼接到目标目录
- 调用
Files.copy()
完成复制
示例代码:
public static void copyDirectory(String sourceDirectoryLocation, String destinationDirectoryLocation)
throws IOException {
Files.walk(Paths.get(sourceDirectoryLocation))
.forEach(source -> {
Path destination = Paths.get(destinationDirectoryLocation,
source.toString().substring(sourceDirectoryLocation.length()));
try {
Files.copy(source, destination);
} catch (IOException e) {
e.printStackTrace();
}
});
}
⚠️ 注意事项:
Files.walk()
默认深度优先遍历,能正确处理嵌套目录- 如果目标路径已存在文件,
Files.copy()
会抛出异常(可通过StandardCopyOption.REPLACE_EXISTING
控制) - 此方法依赖 Java 7+,不适用于老版本
✅ 优点:代码简洁、性能好、支持符号链接和文件属性
❌ 缺点:Java 7 以下不可用
3. 使用 java.io API(兼容旧版本)
如果你还在维护 Java 6 或更早项目,就得靠 java.io.File
+ 手动递归实现。
实现逻辑:
- 检查目标目录是否存在,不存在则创建
- 遍历源目录下的所有条目
- 如果是目录,递归调用自身
- 如果是文件,使用
FileInputStream
和FileOutputStream
复制内容
目录复制主方法:
private static void copyDirectory(File sourceDirectory, File destinationDirectory) throws IOException {
if (!destinationDirectory.exists()) {
destinationDirectory.mkdir();
}
for (String f : sourceDirectory.list()) {
copyDirectoryCompatibityMode(new File(sourceDirectory, f), new File(destinationDirectory, f));
}
}
分发处理方法:
public static void copyDirectoryCompatibityMode(File source, File destination) throws IOException {
if (source.isDirectory()) {
copyDirectory(source, destination);
} else {
copyFile(source, destination);
}
}
文件复制实现:
private static void copyFile(File sourceFile, File destinationFile)
throws IOException {
try (InputStream in = new FileInputStream(sourceFile);
OutputStream out = new FileOutputStream(destinationFile)) {
byte[] buf = new byte[1024];
int length;
while ((length = in.read(buf)) > 0) {
out.write(buf, 0, length);
}
}
}
⚠️ 踩坑提醒:
- 必须手动创建中间目录(
mkdir()
不会创建父目录,建议改用mkdirs()
) source.list()
返回的是文件名数组,不包含路径信息- 建议使用 try-with-resources 确保流正确关闭
✅ 优点:兼容性强,Java 1.4+ 可用
❌ 缺点:代码冗长,易出错,性能一般
4. 使用 Apache Commons IO(最简单)
对于大多数现代 Java 项目,直接使用 Apache Commons IO 是最省事的选择。
添加依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>
💡 注意:Maven 坐标已更新为最新常用版本,避免使用过时的
commons-io:commons-io
一行代码完成复制:
public static void copyDirectory(String sourceDirectoryLocation, String destinationDirectoryLocation) throws IOException {
File sourceDirectory = new File(sourceDirectoryLocation);
File destinationDirectory = new File(destinationDirectoryLocation);
FileUtils.copyDirectory(sourceDirectory, destinationDirectory);
}
✨ 你没看错,就这么一行核心代码。
其他实用方法:
FileUtils.copyDirectoryToDirectory()
:复制目录到另一个目录下FileUtils.copyFile()
:复制单个文件FileUtils.deleteDirectory()
:安全删除整个目录
✅ 优点:代码极简、健壮、经过广泛测试
❌ 缺点:引入额外依赖,对轻量项目可能略重
5. 总结
方法 | Java 版本要求 | 是否推荐 | 适用场景 |
---|---|---|---|
java.nio + Files.walk() |
Java 7+ | ✅ 强烈推荐 | 现代项目,无外部依赖要求 |
java.io + 递归 |
Java 1.4+ | ⚠️ 仅限兼容需求 | 维护老系统 |
Apache Commons IO | Java 1.6+ | ✅ 推荐 | 追求开发效率,已有该依赖 |
📌 最佳实践建议:
- 新项目优先使用 NIO 方式
- 若已引入 Commons IO,直接调用
FileUtils.copyDirectory()
更省心 - 生产环境务必处理异常,避免静默失败
完整示例代码已托管至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-io-3