应避免直接用files.copy(path,path)复制大文件,因其可能一次性读入整个文件导致oom;推荐用inputstream/outputstream流式复制(缓冲区8kb)或filechannel.transferto零拷贝,同时需检查文件可读性、创建父目录、确保流关闭。

Java 中用 Files.copy 复制大文件本身没问题,但直接调用默认方法容易因内存或 I/O 问题失败。关键不是“能不能用”,而是“怎么安全高效地用”。
避免直接用 Files.copy(Path, Path) 复制大文件
这个重载方法底层会尝试一次性读入整个文件(尤其在某些 JVM 实现或文件系统下),对 GB 级文件极易触发 OutOfMemoryError 或长时间阻塞。它适合小文件(如几十 KB),不适合大文件。
推荐方式:用 InputStream / OutputStream 显式流式复制
显式控制缓冲区大小,避免内存暴涨,同时保持简洁。示例代码:
Path source = Paths.get("large-input.zip");
Path target = Paths.get("large-output.zip");
try (InputStream in = Files.newInputStream(source);
OutputStream out = Files.newOutputStream(target)) {
byte[] buffer = new byte[8192]; // 8KB 缓冲区,平衡性能与内存占用
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
说明:
- 缓冲区大小建议 4KB–64KB;8KB 是通用折中值,太大不提升太多性能,太小增加系统调用次数
- 必须用
try-with-resources确保流正确关闭,否则可能句柄泄漏 - 不依赖
Files.copy的自动处理,完全可控
也可用 Files.copy + StandardCopyOption,但需配合通道(Channel)
如果坚持用 Files.copy,可借助 FileChannel 的 transferTo 或 transferFrom(零拷贝,更高效):
try (FileChannel in = FileChannel.open(source, StandardOpenOption.READ);
FileChannel out = FileChannel.open(target, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
in.transferTo(0, in.size(), out); // 支持大文件,内核级传输,不占 JVM 堆内存
}
注意:
- 适用于支持
transferTo的操作系统和文件系统(Linux/Unix 通常 OK,Windows 部分版本有 2GB 限制) - 不能跨文件系统(如从 ext4 到 NTFS 挂载点)时会退化为普通复制,需捕获异常并降级处理
- 仍需确保目标目录存在:
Files.createDirectories(target.getParent())
实用增强建议
实际项目中,复制大文件常需额外保障:
- 提前检查源文件是否存在、是否可读:
Files.isReadable(source) && Files.exists(source) - 确保目标父目录存在:
Files.createDirectories(target.getParent()) - 复制后校验(可选):用
MessageDigest计算 SHA-256 对比,防止静默损坏 - 加进度提示(如每复制 100MB 打印一次):在循环中累计字节数并判断输出
不复杂但容易忽略细节。核心是别让 JVM 背锅——控制缓冲、善用通道、提前兜底,大文件复制就稳了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











