用 io.Copy 复制文件最稳妥,因其内存可控、错误自动传播;需手动同步权限和时间戳,大文件应加校验与断点续传,并发复制须限流避免I/O瓶颈。

用 io.Copy 复制文件最稳妥
Go 标准库没有直接的 “复制文件” 函数,但 io.Copy 是最常用、最可靠的选择。它不关心内容类型,只做字节流搬运,内存占用可控(默认 32KB 缓冲),且自动处理读写错误传播。
常见错误是手动 os.ReadFile + os.WriteFile:小文件看似简单,大文件会吃光内存;而且没做原子性保障,中断时可能留下损坏文件。
- 先
os.Open源文件,再os.Create目标文件(注意用defer dst.Close()) - 调用
io.Copy(dst, src),检查返回的error—— 即使复制了部分数据,出错也要视为失败 - 复制完成后,建议用
dst.Sync()强制刷盘,避免缓存未落盘(尤其对关键数据)
需要保留权限和时间戳?用 os.Stat + os.Chmod + os.Chtimes
io.Copy 只管内容,不碰元数据。若需完整克隆(比如备份场景),必须手动同步 Mode 和 ModTime。
注意:os.Chmod 对 Windows 的只读属性有效,但无法设置 Unix 权限位(如 setuid);os.Chtimes 在某些文件系统(如 FAT32)上可能被忽略。
立即学习“go语言免费学习笔记(深入)”;
- 复制前用
os.Stat(srcPath)获取os.FileInfo - 复制后调用
os.Chmod(dstPath, fi.Mode()) - 再调用
os.Chtimes(dstPath, fi.ModTime(), fi.ModTime())(访问时间和修改时间通常设为一致) - Windows 下若目标已存在且为只读,需先
os.Chmod(dstPath, 0644)再覆盖,否则os.Create会失败
大文件或网络存储场景下,考虑分块校验与断点续传
单纯靠 io.Copy 无法验证完整性,传输中断也无法恢复。生产环境建议加一层校验逻辑。
MD5 或 SHA256 校验成本低、兼容性好;断点续传则依赖服务端支持(如 HTTP Range)或本地记录偏移量。Go 自带 crypto/md5,计算开销可接受(GB 级文件约几百毫秒)。
- 复制过程中用
io.TeeReader将读取流同时写入hash.Hash,避免二次读取 - 校验失败时,不要静默覆盖,应返回明确错误(如
"checksum mismatch for %s") - 若需断点续传,优先用支持的协议(如 rsync over SSH),纯 Go 实现需自行管理 offset 和临时文件,复杂度陡增
并发复制多个文件时,别盲目开 goroutine
文件 I/O 是系统瓶颈,不是 CPU。无限制启 goroutine 反而导致内核调度压力大、磁盘寻道加剧,整体耗时可能更长。
实测表明:在普通 SATA 磁盘上,并发 2–4 个文件复制通常达到吞吐峰值;NVMe 上可略高(6–8),但收益快速衰减。更重要的是控制打开文件数,避免 hit ulimit -n。
- 用
semaphore(如golang.org/x/sync/semaphore)限制并发数,而非runtime.GOMAXPROCS - 每个 goroutine 内部仍用
io.Copy,不要把os.Open放在循环外复用 —— 文件句柄不能跨 goroutine 安全共享 - 注意
os.RemoveAll或os.Rename类操作不是原子的,多 goroutine 同时操作同一目录易出竞态
dst.Close() 失败(磁盘满、只读挂载等),这个 error 必须捕获并返回,否则你以为复制成功了,其实数据根本没落盘。










