Java中复制大文件首选FileChannel的transferTo()实现零拷贝,避免JVM堆内存占用;超2GB需分段(每段≤2GB),用position和remaining控制;通过try-with-resources管理流,关闭流即释放channel。

Java 中用 FileChannel 复制大文件,核心是利用 transferTo() 或 transferFrom() 方法实现零拷贝(zero-copy),避免将大文件内容读入 JVM 堆内存,从而提升性能、减少 GC 压力。
使用 transferTo 实现高效复制
这是最常用的方式,适用于源通道支持 transferTo(如 FileChannel),且目标通道是可写的 FileChannel。底层由操作系统直接在内核空间完成数据传输,不经过用户缓冲区。
- 打开源文件为只读
FileChannel,目标文件为可写(或可读写)FileChannel - 调用
sourceChannel.transferTo(position, count, targetChannel) - 注意:
count参数不能超过Integer.MAX_VALUE(约 2GB),所以对超大文件需分段调用
处理超大文件(>2GB)的分段复制
因为 transferTo 的 count 是 long 类型但实际受限于底层系统调用(如 Linux 的 sendfile64 在某些 JVM 版本中仍受 int 限制),稳妥做法是每次最多传 2GB:
- 用
position控制起始偏移,每次传Math.min(2L * 1024 * 1024 * 1024, remaining) - 循环更新
position和剩余字节数,直到复制完成 - 示例关键逻辑:position += transferred;(
transferred是本次实际传输字节数)
确保资源正确关闭与异常处理
FileChannel 本身不实现 AutoCloseable,但它包装的 FileInputStream / FileOutputStream 是。推荐用 try-with-resources 管理流,再获取其 channel:
立即学习“Java免费学习笔记(深入)”;
- 不要单独关闭
channel,关闭外层流即可自动释放 channel - 捕获
IOException,并考虑在失败时清理已创建的目标文件(如Files.deleteIfExists(targetPath)) - Windows 上若目标文件已打开,复制会失败,需确保无其他进程占用
替代方案:transferFrom + 可选内存映射(仅特定场景)
transferFrom 语义类似,但方向相反(目标 channel 主动从源读)。它在某些 JDK 版本和平台下可能不如 transferTo 高效,尤其是源是普通文件时。
- 如果源文件极小或需随机访问,可考虑
map()映射为MappedByteBuffer,再写入目标 channel(但大文件映射有风险,不推荐) - 纯 Java NIO 复制中,
transferTo是首选;若不可用(如源 channel 不支持),再退回到ByteBuffer+read/write循环


















