必须用 io.copyn 配合 os.open 和 os.create 实现安全分片:它精确控量、不 oom、不切碎二进制;命名需零填充防排序错乱;合并前须清理残留并严格校验哈希。

直接用 io.CopyN 配合 os.Open 和 os.Create,别碰 os.ReadFile 或 bufio.Scanner——前者会 OOM,后者会切碎二进制数据或 panic。
为什么必须用 io.CopyN 而不是手动 Read + Write
io.CopyN 是 Go 唯一能精确控制字节数、不加载全文、不依赖换行符的底层函数。手动 Read 容易漏校验返回值 n,导致末尾少写、多读或零填充;Write 也可能只写入部分数据,忽略 n 就等于静默丢数据。
-
io.CopyN(dst, src, 1024*1024)每次最多写 1MB,返回实际字节数,EOF 时自动停,最后一块不足也完整写出 - 源文件必须用
os.Open打开,不能用os.ReadFile—— 否则 2GB 文件直接 OOM - 目标分片用
os.Create(fmt.Sprintf("part_%03d", i)),零填充命名,否则filepath.Glob("part_*")排序错乱(part_1、part_10、part_2) - 每次调用前不用预判剩余长度:
io.CopyN遇 EOF 返回0或小于请求值,直接 break 即可
io.CopyN 的典型误用和修复
常见错误是把 io.CopyN 当成“保证写满”的函数,然后在 n 时反复重试,结果卡死或重复写入。它本就不承诺写满,而是“最多写这么多”,EOF 就是合法终止条件。
- 错误写法:
if n != chunkSize { log.Fatal("incomplete write") }—— 最后一块永远触发 panic - 正确判断:
if err == io.EOF || n - 别在循环里复用同一个
dst文件句柄:每个分片必须os.Create新文件,写完立刻Close() - 如果要支持断点续传,得自己记录已写偏移,不能靠
io.CopyN自动推算
合并分片时最容易被忽略的三件事
合并不是 cat part_* > original 就完事。顺序错、哈希错、文件残留都会导致静默损坏,几个月后才发现原始文件已删。
- 用
filepath.Glob("part_*")获取列表后,必须提取序号转int排序,sort.Strings不够用 - 合并目标文件用
os.Create新建,别用os.OpenFile(..., os.O_APPEND)—— 若上次中断残留脏数据,append 会叠在前面 - 分割前流式计算一次
sha256.Sum256,合并后再算一次比对;os.Stat().Size()完全不可信
真正的难点不在切,而在切完之后——命名是否防排序错乱、合并是否保序、校验是否覆盖末尾截断和 I/O 错误。这些地方出问题,不会报错,只会让数据在某次部署后突然解析失败。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











