推荐使用 Files.copy(),它底层调用零拷贝机制、默认8KB缓冲、自动处理属性和异常;超大文件可选 FileChannel.transferTo() 实现内核级传输;严禁使用 readAllBytes() 或手动大数组等易致OOM方式。

Java 中复制大文件,核心是避免内存溢出,关键在于用流式处理(streaming)而非一次性加载全文件。推荐使用 Files.copy()(JDK7+)或 FileChannel.transferTo() / transferFrom(),它们底层调用操作系统零拷贝(zero-copy)机制,效率高且不占 JVM 堆内存。
用 Files.copy() 最简单可靠
这是最推荐的方式,代码简洁、自动处理缓冲、支持路径和流,且对大文件友好:
- 内部默认使用 8KB 缓冲区,无需手动管理 byte[] 数组
- 自动处理文件属性(如可选保留最后修改时间)
- 抛出明确的 IOException,便于捕获和重试
示例:
Path source = Paths.get("large-file.zip");
Path target = Paths.get("copy-large-file.zip");
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
用 FileChannel 实现零拷贝(适合超大文件或性能敏感场景)
当文件远大于可用堆内存(如几十 GB),且运行在 Linux/Unix 系统上时,transferTo() 可绕过 JVM 堆,直接在内核空间完成数据传输:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 要求源通道为
FileChannel,目标通道也需支持(如另一个FileChannel) - Windows 上
transferTo()对大于 2GB 的文件可能分段调用,但仍是高效选择 - 注意:不能跨文件系统(如从 ext4 到 NFS)时 fallback 到普通流复制
示例:
try (FileChannel in = FileChannel.open(source, StandardOpenOption.READ);
FileChannel out = FileChannel.open(target, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
in.transferTo(0, in.size(), out);
}
避免常见错误写法
以下方式不适合大文件,务必避开:
- 用
Files.readAllBytes()+Files.write():整文件读进堆内存,极易 OOM - 手动 new 一个超大 byte[](如 100MB)做缓冲:浪费内存,且大小难适配不同环境
- 用
BufferedInputStream+BufferedOutputStream但缓冲区太小(如 1KB):I/O 次数过多,性能差
补充建议
实际项目中可进一步提升健壮性:
- 复制前检查磁盘空间(通过
FileStore.getUsableSpace()) - 对超长路径或特殊字符,统一用
Paths.get()而非字符串拼接 - 需要进度监控时,在循环读写(如用
Channels.newChannel(OutputStream)配合固定缓冲区)中累加已传输字节数

















