files.copy() 默认不覆盖文件,需显式传入 standardcopyoption.replace_existing;复制 inputstream 时须用 try-with-resources 确保流未提前消费;大文件需校验返回字节数并考虑手动缓冲;保留属性仅限同文件系统且需指定 copy_attributes 等选项。

Files.copy() 复制文件时抛出 FileAlreadyExistsException 怎么办
默认行为是拒绝覆盖,直接失败。这不是 bug,而是设计上的安全策略——Java 的 Files.copy() 在目标路径已存在时会严格报错,除非你显式声明覆盖意图。
解决方法是传入 StandardCopyOption.REPLACE_EXISTING:
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
- 不加这个选项,哪怕目标只是个空文件或只读文件,也会抛
FileAlreadyExistsException - 如果目标是目录(而非文件),即使加了该选项,仍会抛
FileAlreadyExistsException—— 因为目录不能被“覆盖”,只能先删后建 - Windows 下对正在被其他进程打开的文件,即使加了
REPLACE_EXISTING也可能触发AccessDeniedException,得换用临时文件 + 原子重命名
用 Files.copy() 把 InputStream 复制到文件,为什么写入内容为空
常见原因是没关闭 InputStream 或忘了用 StandardCopyOption.REPLACE_EXISTING,但更隐蔽的问题在于:你可能误用了 Files.copy(InputStream, Path) 的重载,却没意识到它内部不会自动调用 inputStream.close(),而且流位置可能已被提前消费。
正确做法是确保流可读、未关闭、且从头开始:
try (InputStream is = new FileInputStream(sourceFile)) {
Files.copy(is, targetPath, StandardCopyOption.REPLACE_EXISTING);
}
- 必须用 try-with-resources 管理
InputStream,否则后续复用该流会失败 - 不要传入已调用过
read()或skip()的流,Files.copy()不会重置位置 - 该重载底层调用的是
Channels.newChannel()+transferTo(),在支持的系统上是零拷贝;但如果传入的是ByteArrayInputStream,它会退化为普通字节循环,性能无优势
复制大文件时卡住或内存暴涨,是不是 Files.copy() 有 Bug
不是 Bug,是预期行为受限于 JVM 和 OS 层机制。Files.copy() 本身不分配大缓冲区,但它依赖底层通道传输(如 FileChannel.transferTo),而某些 Linux 内核版本对单次 transferTo 有 2GB 上限,超长文件会被拆成多次调用——若中间某次失败(如磁盘满),不会自动回滚,也不会抛明确异常,而是静默截断。
- 检查返回值:该方法返回实际复制的字节数,务必和源文件大小比对,不等就说明出问题了
- 避免在 NFS 或 CIFS 挂载点上依赖
transferTo,某些网络文件系统不支持高效零拷贝,会降级为用户态缓冲,反而更慢 - 超过几 GB 的文件,建议改用带进度回调的手动缓冲复制(例如 8KB
byte[]循环),便于监控和中断
Files.copy() 能否保留文件权限和时间戳
可以,但仅限于同文件系统内的普通文件复制,且需额外指定选项。
保留最后修改时间用 StandardCopyOption.COPY_ATTRIBUTES;保留所有属性(含权限、所有者、ACL)需配合 PosixFilePermissions 或 FileOwnerAttributeView,但跨文件系统或 Windows 下多数无效。
Files.copy(sourcePath, targetPath,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES);
-
COPY_ATTRIBUTES在 Linux 上通常能保留mtime和atime,但ctime(状态变更时间)永远重置 - 在 Windows 上,它可能保留
Last-Write-Time,但 NTFS 权限(ACL)不会被复制,除非你额外调用Files.setPosixFilePermissions()或使用AclFileAttributeView - 如果源是
InputStream(非Path),COPY_ATTRIBUTES完全无效——因为流没有文件元数据
Files.copy() 不是万能胶水,它的语义强绑定于 Path 和底层文件系统能力。一旦涉及网络存储、容器挂卷、FUSE 文件系统或特殊权限模型,就得退回到手动流控制,并自己处理异常边界和原子性。**Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











