StandardCopyOption 用于控制目标文件存在时的覆盖策略,核心是 REPLACE_EXISTING(直接覆盖)、默认不传选项则抛 FileAlreadyExistsException,且 REPLACE_EXISTING 不自动继承权限或绕过系统锁。

Java 中 `StandardCopyOption` 是 NIO.2 提供的一组标准化复制行为控制选项,它不改变拷贝逻辑本身,而是决定**目标文件已存在时如何响应**。核心作用就是管理覆盖策略,避免默认抛异常中断流程。
覆盖策略的三个关键选项
真正参与覆盖控制的只有以下三个常量,它们互斥使用(不能同时传多个):
-
REPLACE_EXISTING:目标文件存在时直接覆盖(清空重写),不校验内容、不保留原属性(如最后修改时间需额外加
COPY_ATTRIBUTES) -
ATOMIC_MOVE:仅用于
Files.move(),与拷贝无关;若误用于copy()会被忽略 - NOFOLLOW_LINKS:和覆盖无关,只影响符号链接处理方式(跳过链接本身,不解析指向的目标)
不传选项 = 默认拒绝覆盖
这是新手最容易踩的坑。调用 Files.copy(src, dst) 且未指定任何 StandardCopyOption 时,JVM 会严格检查目标路径:
- 若
dst已存在 → 立即抛FileAlreadyExistsException - 即使
dst是空文件或只读文件,也一样失败 - 不会尝试删除、重命名或跳过 —— 行为是“零容忍”
覆盖时要注意的隐含行为
选了 REPLACE_EXISTING 并不等于“完全等价于手动删再拷”。它有几点必须留意:
- 目标文件被截断(truncate)后写入,原有内容彻底丢失,但原文件的 inode(Linux/macOS)或句柄(Windows)可能未立即释放
- 不自动继承源文件权限(如 Unix 的 rwx 或 Windows ACL),除非显式加上
COPY_ATTRIBUTES - 若目标正在被其他进程打开并锁定(例如 Excel 打开的 .xlsx),仍会抛
AccessDeniedException,REPLACE_EXISTING无法绕过系统级锁
安全覆盖的推荐组合
生产环境建议搭配使用,兼顾健壮性与语义清晰:
-
StandardCopyOption.REPLACE_EXISTING+StandardCopyOption.COPY_ATTRIBUTES:覆盖同时尽量保留时间戳、只读标记等基础属性 - 若需更高一致性,应在 copy 前用
Files.exists(dst)预检,失败时主动记录或告警,而不是依赖异常捕获做流程分支 - 绝对不要依赖
REPLACE_EXISTING来“修复”权限问题——它不改目标父目录的写权限,如果父目录不可写,照样失败










