按字节大小分割文件应使用 io.copyn 精确控制每块字节数,避免 bufio.scanner 或 os.readfile;需用 os.open 读源文件、os.create 命名零填充分片,合并时严格排序并 sha256 校验。

按文件大小分割写入,核心是控制每个输出文件的字节数上限,而不是依赖行边界或缓冲区自动切分;io.CopyN 是最稳的底层手段,别碰 bufio.Scanner 或 os.ReadFile。
用 io.CopyN 实现固定字节切分
io.CopyN 是 Go 标准库中唯一能精确控制复制字节数且不加载全文进内存的函数。它直接操作 io.Reader 和 io.Writer,适合 GB 级日志、dump 文件等场景。
- 每次调用
io.CopyN(dst, src, chunkSize),最多复制chunkSize字节,返回实际写入数;返回 0 表示已到 EOF - 源文件必须用
os.Open打开,不能用os.ReadFile—— 否则 1GB 文件直接 OOM - 目标分片用
os.Create(fmt.Sprintf("part_%03d", i))创建,零填充命名防排序错乱 - 无需手动判断剩余长度:当
io.CopyN遇到 EOF 时自动停止,最后一个小于chunkSize的块会被完整写出
为什么不能用 bufio.Scanner 或循环 Read
Scanner 是单向流式读取器,Scan() 调用后文件指针不可回退,无法用于“定位 + 截断”式切分;而手动循环 Read() 容易因缓冲区大小不匹配导致末尾字节丢失或越界。
-
bufio.Scanner默认缓冲区 64KB,遇到超长行(如含 base64 的 JSON)会 panic - 想从第 500MB 处开始切第二块?必须重开文件 + 重新扫描——时间复杂度 O(N²),且无法并行预估偏移
- 反复
os.Open+Scanner易耗尽系统 fd,尤其在高并发切分时 - 手动
Read()若未校验返回值n,可能把部分读取误认为 EOF,造成数据截断
合并时顺序和校验不能省
合并不是简单 cat part_*,而是必须按逻辑序号顺序追加,并用哈希确认内容一致——否则静默损坏可能几个月后才暴露。
- 用
filepath.Glob("part_*")获取文件列表后,必须sort.Strings或提取序号转整数排序,避免part_1、part_10、part_2错序 - 合并目标文件用
os.Create新建,不要用os.OpenFile(..., os.O_APPEND)—— 并发或未清空时易出错 - 每个分片打开后直接
io.Copy(mergedFile, partFile),完成后Close(),别用bytes.Buffer拼接——大分片会爆内存 - 分割前用
sha256.Sum256+io.Copy流式计算原始哈希;合并后再算一次比对,os.Stat().Size()不足以验证完整性
二进制文件与文本文件要区分策略
按大小切分本身不关心内容,但后续用途决定是否需额外处理。若目标是传输或归档,纯字节切分即可;若后续要解析为文本(比如日志),必须确保每块以完整行为界——这时得回溯找换行符。
- 先用
file.ReadAt([]byte{0}, 0)读首字节,检查是否在 ASCII 可见字符范围(0x20–0x7E)或合法 UTF-8 头,初步判断是否为文本 - 若不确定,宁可放弃“按行对齐”,改用纯字节切分 + 零填充命名 + SHA256 校验,这是最稳 fallback
- 绝对不要混合策略:比如“前 100MB 按行,后面按字节”——合并逻辑断裂,维护成本陡增
- 真正麻烦的不是写不对,而是写对了却没校验;数据损坏往往在原始文件被清理后才被发现
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











