io.Copy最省心但需注意三点:不校验源是否为目录、不创建目标父目录、不保留权限和时间戳;应配合os.Stat、os.MkdirAll、os.Chmod、os.Chtimes使用。

直接用 io.Copy 最省心,但要注意缓冲区和错误处理
绝大多数场景下,io.Copy 是首选:它内部自动使用 32KB 缓冲区,兼顾性能与内存占用,且能正确处理流式读写。但容易忽略两点:io.Copy 不校验源文件是否为目录、不创建目标路径父目录、也不保留文件权限和时间戳。
- 务必先用
os.Stat检查源文件是否存在且非目录 - 目标路径的父目录需提前用
os.MkdirAll创建,否则会报no such file or directory -
io.Copy返回的是实际拷贝字节数和第一个遇到的错误,不能只看 err 是否为 nil —— 要检查返回的n是否等于源文件大小(尤其在需要强一致性时)
src, _ := os.Open("a.txt")
dst, _ := os.Create("b.txt")
n, err := io.Copy(dst, src)
if err != nil {
log.Fatal(err)
}
fmt.Printf("copied %d bytes\n", n)
用 io.CopyBuffer 手动控制缓冲区大小,适合大文件或内存受限环境
当拷贝单个超大文件(如 >1GB),或运行在嵌入式/容器等内存紧张环境时,io.CopyBuffer 允许你传入自定义缓冲区切片,避免默认 32KB 在高频小文件场景下反复分配。
- 缓冲区太小(如 4KB)会增加系统调用次数,降低吞吐;太大(如 1MB)可能引发 GC 压力或 OOM
- 建议按场景选值:普通服务用
make([]byte, 64*1024)(64KB),IoT 设备用make([]byte, 8*1024) - 缓冲区必须是切片(
[]byte),不能是数组;重用同一缓冲区时注意并发安全
buf := make([]byte, 64*1024)
src, _ := os.Open("large.bin")
dst, _ := os.Create("large_copy.bin")
_, err := io.CopyBuffer(dst, src, buf)
if err != nil {
log.Fatal(err)
}
完整文件拷贝需组合 os.OpenFile + os.Chmod + os.Chtimes
仅靠 io.Copy 得到的是“内容一致”,但生产环境常要求元数据一致:权限、修改时间、访问时间。Go 标准库不提供原子化“复制+保留属性”的函数,必须手动补全。
- 权限需用
os.Chmod(dst, info.Mode()),注意info.Mode()包含权限位和文件类型位,传给Chmod前应 &os.ModePerm - 时间戳用
os.Chtimes(dst.Name(), info.ModTime(), info.ModTime())(访问时间通常也设为同值) - 符号链接、设备文件等特殊类型需额外判断
info.Mode() & os.ModeSymlink != 0,否则os.Open会跟随链接导致误拷内容
src, _ := os.Open("src.go")
info, _ := src.Stat()
dst, _ := os.OpenFile("dst.go", os.O_CREATE|os.O_WRONLY, info.Mode()&os.ModePerm)
io.Copy(dst, src)
dst.Close()
os.Chtimes("dst.go", info.ModTime(), info.ModTime())
第三方库 fsutil.Copy 或 copy.Copy 看似方便,但引入依赖前请确认需求边界
像 github.com/anatol/copy 或 golang.org/x/exp/fs/copy(实验包)封装了递归、符号链接处理、进度回调等功能,但多数项目并不需要这些。
本文档主要讲述的是Android使用ViewFlipper做页面切换;Android系统自带有一个多页面管理的控件:ViewFlipper.它可以简单实现子页面的切换,它只需使用addView方法添加几个View,每个View对应的是一个页面,即可完成对于多页面的管理。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
立即学习“go语言免费学习笔记(深入)”;
- 如果只是单文件、无 symlink、不跨文件系统,标准库已足够,无需额外依赖
-
copy.Copy对硬链接、ACL、扩展属性等仍不支持,别误以为它是“完全替代” - 某些库默认启用递归(如
fsutil.Copy),若传入目录路径却没加判断,可能意外拷贝整个子树
真正复杂的需求(如 rsync 风格同步)不如直接调用 rsync -a 命令,Go 只做 process wrapper —— 更可靠,也省去自己处理 edge case 的成本。









