用 io.Copy 复制文件最稳妥,它流式读写、内存友好且自动处理 EOF 和部分写;需手动创建目标文件、检查源文件类型、关闭文件句柄,并额外调用 os.Chmod/os.Chtimes 保留权限与时间戳。
用 io.Copy 复制文件最稳妥
Go 标准库不提供类似 cp 的单函数封装,但 io.Copy 是最常用、最可靠的选择。它底层按缓冲区(默认 32KB)流式读写,内存友好,且自动处理 EOF 和部分写场景。
常见错误是直接用 os.ReadFile + os.WriteFile 处理大文件——这会把整个文件加载进内存,极易 OOM。
- 务必先创建目标文件:用
os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, srcInfo.Mode()) - 复制前建议用
os.Stat检查源文件是否存在且为普通文件,避免复制目录或符号链接时出错 - 记得关闭源和目标
*os.File,推荐用defer或errgroup统一处理
src, _ := os.Open("a.txt")
dst, _ := os.OpenFile("b.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
defer src.Close()
defer dst.Close()
io.Copy(dst, src) // 返回实际字节数和 error
需要保留权限和时间戳?用 os.Chmod 和 os.Chtimes
io.Copy 只负责内容,不会继承源文件的 mode、modtime、atime。若需完整克隆(如备份场景),必须手动设置。
注意:os.Chtimes 在 Windows 上只支持修改修改时间(mtime),访问时间(atime)被忽略;Linux/macOS 则两者都生效。
- 权限位要从源文件
os.FileInfo.Mode()中提取,别硬写0644—— 可执行文件或 socket 文件会丢失可执行位或特殊属性 - 调用
os.Chtimes前确保目标文件已关闭,否则部分系统会返回EBUSY - 如果目标路径父目录不存在,
os.OpenFile会失败,需提前用os.MkdirAll(filepath.Dir(dstPath), 0755)
复制目录怎么办?别手写递归,用 filepath.WalkDir + os.MkdirAll
Go 1.16+ 的 filepath.WalkDir 比老版 filepath.Walk 更高效(避免重复 Stat),适合遍历源目录结构。