不能用 md5.Sum 算大文件,因其是值类型,内部缓存全部输入数据,等同于全量加载进内存;1GB 文件即占 1GB 内存,易触发 OOM 或 GC 崩溃,仅适用于短字符串如 URL、配置键。

md5.Sum 或 os.ReadFile 计算大文件 MD5 会 OOM,必须用 md5.New() 配合 io.Copy 流式处理,内存恒定约 32KB。
为什么不能用 md5.Sum 算文件?
md5.Sum 是为小数据设计的值类型,它把整个输入缓存在结构体内;传入大文件字节切片等于强制加载全量内容进内存。1GB 文件就占 1GB 内存,GC 压力陡增,甚至触发系统 OOM kill。
- 错误写法:
data, _ := os.ReadFile("big.zip"); md5.Sum(data) -
md5.Sum([]byte(s))只适合 URL、配置键这类短字符串( - 打印
md5.Sum结构体本身不报错,但输出是{[187 242 109 ...]}这类字节序列,不是你想要的 32 位 hex 字符串
md5.New() + io.Copy 是唯一可靠路径
这是标准流式哈希模式:md5.New() 返回一个 hash.Hash 接口,满足 io.Writer,可直接受 io.Copy 驱动,无需手动分块、不用管 buffer 大小。
- 正确流程:打开文件 → 创建 hasher →
io.Copy(hasher, file)→ 调hasher.Sum(nil) -
io.Copy默认使用 32KB 缓冲区,对磁盘 I/O 已足够高效 - 别写
hasher.Write(buf)手动循环——容易漏读最后不足一整块的数据 - 别传非 nil 切片给
Sum,如hasher.Sum([]byte("x")),会把 "x" 拼进结果里
如何同时保存文件并计算 MD5?
上传或下载场景常见需求:不想先写磁盘再重读一遍(浪费 I/O),要用 io.MultiWriter 合并写入目标和哈希器。
- 示例:
mw := io.MultiWriter(dstFile, hasher),然后io.Copy(mw, srcReader) -
srcReader可以是*os.File、http.Request.Body、bytes.Reader等任意io.Reader - 注意:两个 writer 必须能独立完成写入;若 dstFile 写失败,哈希仍会继续算,需自行检查
io.Copy返回的 error
容易被忽略的资源与错误细节
MD5 计算本身几乎不会出错,但 os.Open 和 io.Copy 阶段失败极频繁,且错误类型五花八门。
立即学习“go语言免费学习笔记(深入)”;
- 漏写
defer f.Close()→ fd 泄露,Linux 默认最多 1024 个 open file,跑几次就卡死在too many open files -
os.Open可能返回permission denied、is a directory、no such file or directory,这些全是系统调用错误,不是 crypto/md5 的问题 -
io.Copy的 error 必须检查,比如网络中断、磁盘满、权限变更等都会在这里暴露 - 算完后不能再对同一个
hasher调Write——Sum不重置状态,继续写会导致拼接哈希,不是新摘要


















