Golang如何拷贝文件_Golang文件拷贝操作详解

8次阅读

io.copy是最稳妥的默认文件拷贝方式,自动处理缓冲、分块读写和错误传播,但不检查目录、不创建父目录、不保留权限与时间戳;go 1.19+推荐使用os.CopyFile。

Golang如何拷贝文件_Golang文件拷贝操作详解

io.Copy 是最稳妥的默认选择

绝大多数情况下,直接用 io.Copy 拷贝文件就够了——它自动处理缓冲(默认 32KB)、分块读写、错误传播,不关心文件大小,GB 级文件也不会爆内存。

但要注意三点:它只管字节流,不检查源是不是目录;不创建目标路径的父目录;也不保留权限、时间戳等元信息。

  • 必须手动调用 os.Openos.Create,并确保用 defer file.Close()
  • 目标路径的父目录不存在时,os.Create 会直接报 no such file or Directory,得提前用 os.MkdirAll(filepath.Dir(dst), 0755)
  • 若需校验完整性,可对比 io.Copy 返回的字节数与 source.Stat().Size()

想保留权限和修改时间?得手动补全 os.Chmodos.Chtimes

io.Copy 复制完只是内容一致,目标文件的权限可能是默认的 0644,时间戳是当前时间。对可执行脚本、配置文件或备份场景,这往往不够。

正确做法是先 source.Stat() 获取源文件信息,再分别设置:

立即学习go语言免费学习笔记(深入)”;

  • 权限:用 os.Chmod(dst, info.Mode() & os.ModePerm)(注意 & os.ModePerm,否则可能误设文件类型位)
  • 时间戳:用 os.Chtimes(dst, info.ModTime(), info.ModTime()),第二个参数是访问时间,第三个是修改时间
  • windows 下 os.Chmod 对部分权限位无效,别指望完全还原 linux0755

大文件卡住?先排查是否漏了 Close 或路径不存在

现象是程序在 io.Copy 调用处长时间无响应,CPU 低、磁盘没动静——这通常不是 io.Copy 本身的问题,而是 I/O 阻塞在上游或下游。

  • 最常见原因是目标路径父目录不存在,os.Create 失败但你没检查 Error,后续 dstnilio.Copy(dst, src) 会 panic 或静默卡死
  • 另一个高频问题是忘了 defer src.Close(),尤其在循环拷贝多个文件时,句柄耗尽后新 os.Open 就会阻塞
  • 如果目标是网络文件系统(如 NFS),延迟高可能导致单次 Write 阻塞,此时可考虑用 io.CopyBuffer 指定更大缓冲区(如 64 * 1024)减少系统调用频次

Go 1.19+ 推荐直接用 os.CopyFile

如果你用的是 Go 1.19 或更高版本,os.CopyFile(src, dst, 0) 是更优解:它内部已封装权限继承、原子性 rename、临时文件中转和错误重试逻辑,比手写 io.Copy 更健壮。

但它不支持跨文件系统硬链接或 reflink,遇到只读文件也更友好;旧版本可通过升级或引入 golang.org/x/tools/go/packages 兼容层替代。

唯一限制是它不提供进度回调或自定义缓冲区,如需监控拷贝进度,还是得回退到 io.Copy + io.TeeReader 组合。

真正容易被忽略的不是怎么写,而是「谁来保证父目录存在」「谁来处理符号链接」「谁来应对磁盘满时的半截文件」——这些边界问题不会在小样例里暴露,但上线后往往第一个出事。

text=ZqhQzanResources