io.CopyN是唯一能精确按字节边界切分且不加载全文的方案,因它通过file.Seek定位偏移、io.CopyN控制长度实现流式切分,避免os.ReadFile导致OOM;必须校验sha256且文件名需数字排序防错位。

用 io.CopyN 切分大文件时为什么必须控制偏移和长度
直接读全量再切片(比如用 os.ReadFile)会 OOM,尤其处理 GB 级视频或数据库 dump;io.CopyN 是唯一能精确按字节边界切分、且不加载全文的方案。
- 每次调用前需用
file.Seek(offset, io.SeekStart)定位起始位置,否则切出来的块内容错位 -
io.CopyN(dst, src, chunkSize)返回实际复制字节数,必须检查是否为 0 —— 这是 EOF 的唯一可靠信号 - 最后一块可能小于
chunkSize,io.CopyN自动处理,无需额外判断剩余长度 - 别用
bufio.Scanner或ReadString切二进制文件,它们按行逻辑破坏数据完整性
合并时文件名排序错位导致数据损坏的真实原因
filepath.Glob("part_*.bin") 返回 part_1、part_10、part_2 是正常行为,不是 Go bug,而是字符串字典序天然缺陷。按此顺序合并,PDF 直接打不开,ZIP 解压报 CRC 错。
- 生成分片时强制零填充:
fmt.Sprintf("part_%03d.bin", i)→part_001.bin - 读取时不能依赖
sort.Strings,必须提取数字:extractNum("backup_2024_part_042")返回 42,再用sort.Slice排序 - 别信
os.ReadDir返回顺序 —— ext4 和 NTFS 都不保证,Linux 下甚至可能每次运行结果不同
为什么 os.Create 是合并目标文件的唯一安全选择
用 os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_APPEND) 写首次合并文件,行为等价于普通写入;但若该文件已存在,后续追加会污染数据,尤其并发上传场景下极易丢块。
-
os.Create(dstPath)自动清空并覆盖,语义明确,无歧义 - 每个分片用
os.Open后直传io.Copy(mergedFile, partFile),中间不经过[]byte缓冲 - 若需强一致性(如金融级日志),每拷完一块调一次
mergedFile.Sync();纯吞吐场景可省,性能提升明显 - 千万别用
bytes.Buffer.Write或strings.Join拼接 —— 分片数一多,内存直接爆掉
校验环节漏掉 sha256.Sum256 比对等于没合并
os.Stat().Size 一致 ≠ 内容正确。末尾几个字节丢失、某块被截断、I/O 中断未写满 —— 这些都可能导致大小不变但文件不可用,而 PDF、MP4、SQLite 等格式对此极其敏感。
立即学习“go语言免费学习笔记(深入)”;
- 分割前:用
sha256.New()+io.Copy流式算原始哈希,不加载全文 - 合并后:对新文件做同样哈希计算,对比两个
[32]byte值是否相等 - 校验失败必须立刻删掉目标文件和所有分片 —— 留着脏数据比报错更危险
- 别用
md5,碰撞风险高;也别跳过校验,"写对了却没校验"才是真麻烦



















