Apache Commons-IO 2.9+ Windows复制目录权限继承问题及解决咨询
Commons-IO 2.9+ Windows目录复制权限继承问题解决方法
在Windows系统中,使用commons-io@2.9及以上版本的FileUtils类调用FileUtils.copyDirectory(...)方法复制目录时,其行为与Windows默认复制行为存在差异。
默认情况下,对象会在创建或复制/移动到父文件夹时继承父对象的权限。唯一例外是在同一卷上将对象移动到不同文件夹时,会保留原权限。
预期行为:
- 复制到目标位置的文件继承父目录权限
实际行为:
- 复制到目标位置的文件不继承父目录权限
这一问题十分关键,因为Windows历来由系统管理权限,手动设置易引发更多错误,导致该方法无法满足Windows下的常见使用场景。
版本行为测试结果
经测试,这是一个行为退化问题,各版本表现如下:
| 版本 | 状态 |
|---|---|
commons-io@1.1(2005) | ✅ 继承目标目录权限 |
commons-io@2.4(2013) | ✅ 继承目标目录权限 |
commons-io@2.5(2016) | ✅ 继承目标目录权限 |
commons-io@2.6(2017) | ✅ 继承目标目录权限 |
commons-io@2.7(2020) | ✅ 继承目标目录权限 |
commons-io@2.8(2020) | ✅ 继承目标目录权限 |
commons-io@2.9(2021) | 🚫 不继承目标目录权限 |
commons-io@2.10(2021) | 🚫 不继承目标目录权限 |
commons-io@2.11(2021) | 🚫 不继承目标目录权限 |
权限对比(以复制到C:\Program Files为例)
| 版本 | 权限(icacls <file>) |
|---|---|
commons-io@2.8 | NT AUTHORITY\SYSTEM:(I)(F)BUILTIN\Administrators:(I)(F)BUILTIN\Users:(I)(RX)APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX) |
commons-io@2.9 | NT AUTHORITY\SYSTEM:(F)BUILTIN\Administrators:(F)WIN10ARM\owner:(F) |
测试示例
示例代码:
import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; public class Main { private static final String PROGRAM_FILES = System.getenv().get("ProgramFiles"); public static void main(String ... args) throws IOException { // 准备测试文件夹 File folder = new File("MyApp"); folder.mkdirs(); File file = new File(folder, "test.txt"); file.createNewFile(); // 使用FileUtils复制目录 File parent = new File(PROGRAM_FILES); File dest = new File(parent, "MyApp"); System.out.println(String.format("创建目标父文件夹 %s...", dest)); dest.mkdirs(); System.out.println(String.format("复制内容从 %s 到 %s...", folder, dest)); FileUtils.copyDirectory(folder, dest); // 测试权限可执行命令: // icacls "%ProgramFiles%\MyApp\test.txt" } }
编译代码:
javac -cp lib\commons-io-2.8.jar src\Main.java
运行代码(需以管理员身份打开CMD):
java -cp lib/commons-io-2.8.jar;src Main
测试权限:
icacls "%ProgramFiles%\MyApp\test.txt"
测试后手动删除%ProgramFiles%\MyApp,更换commons-io-2.9.0.jar重复测试即可对比差异。
不降级Commons-IO的解决方案
要恢复旧的权限继承行为,需自定义文件复制逻辑,让Windows系统自动处理权限继承,绕过Commons-IO 2.9+的权限复制逻辑:
- 实现自定义目录复制工具
递归遍历源目录,创建目标目录时自动继承父权限,复制文件时不手动传递源文件权限,依赖Windows默认机制:
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; public class WindowsFileCopyUtils { public static void copyDirectory(Path sourceDir, Path targetDir) throws IOException { Files.createDirectories(targetDir); Files.list(sourceDir).forEach(sourcePath -> { Path targetPath = targetDir.resolve(sourcePath.getFileName()); try { if (Files.isDirectory(sourcePath)) { copyDirectory(sourcePath, targetPath); } else { Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); } } catch (IOException e) { throw new RuntimeException("复制失败: " + sourcePath, e); } }); } }
- 替换原有调用
将代码中FileUtils.copyDirectory(folder, dest)替换为:
WindowsFileCopyUtils.copyDirectory(folder.toPath(), dest.toPath());
这样就能让复制的文件自动继承目标父目录的权限,与Commons-IO 2.8及更早版本行为一致。
内容的提问来源于stack exchange,提问作者tresf
相关产品推荐
相关产品推荐

