os.OpenFile的flags参数需按意图精确选择:覆盖用O_CREATE|O_WRONLY|O_TRUNC,追加用O_CREATE|O_WRONLY|O_APPEND,防误覆盖加O_EXCL;文件名排序须零填充或手动提取数字排序;合并用io.Copy流式搬运,禁用ReadFile/Buffer;必校验哈希且显式写入分隔符。

os.OpenFile 的 flags 参数必须按意图选,不是“能打开就行”
合并多个数据源到单个文件,第一步就卡在目标文件怎么开。用错 os.O_APPEND 或漏掉 os.O_TRUNC,轻则内容错位,重则旧数据残留、新数据从中间覆写。
常见错误现象:
- 第二次运行后文件变大一倍 → 用了
os.O_APPEND但本意是覆盖重做 - 合并完打开是乱码或解析失败 → 二进制文件(如 PDF)被当成日志追加,实际该用覆盖模式
- 首次成功、二次 panic → 目标文件已存在,
os.Create返回 error,代码没处理 fallback
实操建议:
- 想覆盖生成全新文件:用
os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) - 想追加到已有日志末尾:用
os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644),且确保目标文件存在(否则 Windows 下可能报ENOENT) - 想防止误覆盖:加
os.O_EXCL,仅首次创建有效,第二次直接失败,适合一次性归档场景
文件名排序不能信 filepath.Glob 或 os.ReadDir 的默认顺序
Go 不保证 filepath.Glob("data/*.log") 或 os.ReadDir 返回的文件顺序是自然序。字符串排序下 part_1.log、part_10.log、part_2.log 会变成 1→10→2,合并后数据彻底错位。
立即学习“go语言免费学习笔记(深入)”;
实操建议:
- 生成分片时就强制零填充:
fmt.Sprintf("part_%03d.log", i)→ 得到part_001.log、part_002.log,字典序即自然序 - 读取前手动排序:提取文件名中数字,转
int比较,比如strings.TrimSuffix(strings.TrimPrefix(f.Name(), "part_"), ".log")后strconv.Atoi - 别用
filepath.Walk控制顺序 —— 它返回顺序不稳定,Linux 和 Windows 行为不一致
io.Copy 是流式搬运核心,别碰 os.ReadFile 或 bytes.Buffer
用 os.ReadFile 合并 10 个 100MB 文件,内存直接吃掉 1GB;用 bytes.Buffer 拼接,本质还是全量加载,还多一次内存拷贝。真正稳又快的做法,是让 io.Copy 直接在两个 *os.File 之间搬运字节流。
实操建议:
- 每个源文件用
os.Open(src)打开,传给io.Copy(dst, src),不缓存、不拼接、不加载全文 - 若需在文件间加换行或分隔符(如
"\n---\n"),单独调dst.WriteString,别塞进io.Copy - 并发读多个小文件写入同一目标?多数情况更慢 —— 磁盘寻道加剧、缓冲区竞争,单 goroutine +
io.Copy足够应付 SSD/NVMe - 大文件合并卡住?检查是否用了
bufio.Scanner或逐行ReadString—— 它们破坏二进制完整性,且比io.Copy慢一个数量级
合并后必须校验哈希,os.Stat().Size == 原始总和 ≠ 内容正确
文件大小对得上,不代表内容没损坏。I/O 中断、io.Copy 返回值未检查、末尾多写/少写几字节,都会导致 PDF 打不开、ZIP 解压 CRC 错误、视频播放卡顿。
实操建议:
- 分割前计算原始哈希:
h := sha256.New(); io.Copy(h, srcFile); originalSum := h.Sum(nil) - 合并后立即重算:
dstFile.Seek(0, 0); io.Copy(sha256.New(), dstFile) - 对比哈希用
bytes.Equal(a, b),别用==比较切片(比较的是底层数组指针) - 追加日志类文件,每次写完建议调一次
dst.Sync(),防断电时最后几 KB 没落盘
最易被忽略的一点:分隔符必须显式写入。无论文本还是二进制,io.Copy 只搬原始字节,不会自动加换行或空格。如果多个源文件末尾没换行,又没手动 WriteString("\n"),合并后两段内容就会粘连 —— 这种问题往往要等到解析时报错才暴露。


















