Java Files.copy方法文件覆盖目录问题及防范方案咨询
问题描述
源路径为普通文件、目标路径对应位置已存在同名目录时,执行Java的Files.copy方法复制源文件到目标路径,会出现原有目标目录被源文件直接覆盖的情况。要避免该问题,是否只能在复制操作前调用Files.isDirectory、Files.isRegularFile方法提前校验路径类型?
复现环境
- 操作系统:CentOS Linux release 7.4.1708 (Core)
- JDK版本:1.8.0_162
复现步骤与代码
- 执行以下命令准备测试环境
# 创建源文件所在目录 mkdir -p /tmp/a # 编辑生成普通源文件 /tmp/a/aa vi /tmp/a/aa # 创建目标位置同名目录 mkdir -p /tmp/b/bb
- 编写测试Java代码并执行
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; public class FilesCopyMain{ public static void main(String[] args) throws IOException{ Path from = Paths.get("/tmp/a/aa"); Path to = Paths.get("/tmp/b/bb"); Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); } }
解答
不需要仅依赖前置调用类型校验方法规避问题,先明确问题根因:传入StandardCopyOption.REPLACE_EXISTING参数时,JDK8版本的Files.copy实现不会对已存在目标路径的类型做校验,只要进程持有对应路径的写权限,就会直接执行替换操作,因此会出现目录被普通文件覆盖的异常表现。
可根据业务场景选择以下任意一种规避方案:
- 前置类型校验:即手动判断路径类型的方案,复制前先检查目标路径的存在状态与类型,如果目标已存在且为目录,直接终止复制、抛出异常或者走自定义目录处理逻辑(比如将文件写入目录内部、执行目录内容合并等)。如果运行环境存在软链接,校验时建议传入
LinkOption.NOFOLLOW_LINKS参数,避免跟随软链接导致校验结果不符合预期。参考实现:
// 不跟随软链接校验目标路径状态 if (Files.exists(to, LinkOption.NOFOLLOW_LINKS)) { if (Files.isDirectory(to, LinkOption.NOFOLLOW_LINKS)) { throw new IOException("目标位置已存在同名目录,禁止覆盖"); } } Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
- 移除
REPLACE_EXISTING复制参数:如果业务规则不允许覆盖任何已存在的路径,直接去掉该复制选项即可。默认配置下,只要目标路径已存在(无论类型是文件还是目录),Files.copy会直接抛出FileAlreadyExistsException,从根源上避免覆盖已有路径,不需要额外编写校验逻辑。 - 升级JDK版本:JDK11及后续官方版本修正了该逻辑,即使传入
REPLACE_EXISTING参数,当检测到目标已存在路径为目录时,会直接抛出FileSystemException,不会执行目录覆盖操作,无需额外编写前置校验代码。
内容的提问来源于stack exchange,提问作者sinh
相关产品推荐
相关产品推荐

