io.Copy复制文件时目标为空是因为未正确打开或关闭目标文件;需用os.Create或os.OpenFile可写模式打开并显式调用dst.Close();不能用os.Open(只读)或os.ReadFile(非io.Reader);勿额外包装bufio或使用bytes.Buffer中转;元数据如权限、时间戳需手动同步;进度与中断需自行实现分块复制或包装Reader。

io.Copy 复制文件时为啥目标文件总是空的
因为 io.Copy 本身不处理文件打开/关闭,只负责在两个 io.Reader 和 io.Writer 之间搬数据。如果目标文件没正确打开为可写、或没关闭,数据就丢了。
- 必须用
os.Create或os.OpenFile(..., os.O_CREATE|os.O_WRONLY|os.O_TRUNC)打开目标文件,os.Open是只读的,会直接 panic - 复制完务必调用
dst.Close(),否则缓冲区可能没刷到磁盘(尤其小文件容易误以为成功) - 源文件要用
os.Open,别用os.ReadFile后传字节切片——那不是io.Reader,不能直接喂给io.Copy
复制大文件时卡住或内存暴涨
io.Copy 默认用 32KB 缓冲区,对 GB 级文件足够稳;但如果你手动包装了 bufio.Reader 或 bufio.Writer,反而可能因缓冲区叠加导致延迟写入或死锁。
- 直接传
*os.File给io.Copy就行,它内部已优化,无需额外包装 - 避免用
bytes.Buffer中转:比如先io.Copy(&buffer, src)再io.Copy(dst, &buffer)—— 这会把整个文件读进内存 - 跨设备复制(如 SSD → NFS)时,系统调用延迟高,
io.Copy会自然变慢,这不是 bug,是 IO 特性
复制后文件权限丢失或时间戳不对
io.Copy 只管内容,不管元数据。新文件默认是 0644,且修改时间是创建时刻,和原文件无关。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 用
os.Stat读原文件的Mode(),再用os.Chmod(dst, mode)补权限 - 用
os.Chtimes(dst, srcInfo.ModTime(), srcInfo.ModTime())同步时间戳(注意:Windows 上访问时间不可靠,只设修改时间即可) - 符号链接、扩展属性、ACL 等完全不会被复制,
io.Copy不处理这些
需要带进度提示或中断支持怎么办
io.Copy 没内置进度回调,也不能安全中断;强行 kill goroutine 容易留下半截文件。
- 用
io.CopyN分块复制(比如每次 1MB),每块后检查是否收到中断信号 - 自己实现
io.Reader包装源文件,读取时更新计数器并响应context.Context的Done() - 别用
time.Sleep模拟进度——真实场景下 IO 速度波动大,固定 sleep 会误导用户
真正麻烦的从来不是 io.Copy 本身,而是关掉它之后那些没人帮你干的事:关文件、设权限、同步时间、处理中断。漏掉任意一个,上线后都可能变成凌晨三点的告警。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










