必须用os.open+io.copy+hash.hash流式计算,否则os.readfile或md5.sum会全量加载致oom;需每次新建哈希实例、检查错误、defer file.close()并用hex.encodetostring转哈希字符串。

大文件哈希计算不能用 os.ReadFile 或 md5.Sum,否则极易触发 OOM;必须走流式路径:用 os.Open + io.Copy + hash.Hash 实例,内存占用恒定在 ~32KB。
为什么 os.ReadFile 会崩掉大文件
它把整个文件一次性读进内存。一个 1.8GB 的 ISO 文件,在 4GB 内存机器上可能直接被系统 OOM kill;即使没崩,GC 压力也会陡增,延迟飙升。而 io.Copy 默认用 32KB 缓冲区,边读边喂哈希器,全程无额外拷贝、不放大内存占用。
-
os.ReadFile("big.iso")→ 全量加载,风险高 -
file, _ := os.Open("big.iso"); io.Copy(hasher, file)→ 流式分块,安全可控 - 漏写
defer file.Close()会导致 fd 泄露,Linux 默认最多 1024 个 open file,跑几次就卡死在too many open files
sha256.New() 和 sha256.Sum256 别混用
sha256.New() 返回的是 hash.Hash 接口,支持流式写入;sha256.Sum256 是值类型,内部缓存全部输入数据,只适合小字符串(比如 token、密码),对文件用它等于变相调用 ReadFile。
- 多文件校验时,每次必须新建
sha256.New()实例——复用同一个实例算两个文件,第二个结果是拼接哈希,不是独立摘要 -
hasher.Sum(nil)返回的是原始字节切片,要转十六进制字符串,必须用hex.EncodeToString(hasher.Sum(nil)),不能用fmt.Sprintf("%x", hasher.Sum(nil)),后者会打印结构体字段而非哈希值 - 没有
sha256.File()这种函数,别在文档里白搜
SHA256 还是 MD5?看场景选,别默认抄 MD5
MD5 算得快,但已不抗碰撞,仅适合内部快速比对(如构建缓存 key);生产环境做完整性校验,必须用 crypto/sha256。
- CDN 回源校验、镜像分发、断点续传验证等场景,SHA256 是事实标准
- 如果服务端只提供 MD5,那是兼容性妥协,不是技术推荐
- 算法切换只需改 import 和 New() 调用,其余逻辑完全一致:
crypto/md5→md5.New(),crypto/sha256→sha256.New()
最容易被忽略的其实是错误传播和资源释放:每个 os.Open 都要配 defer Close(),每个 io.Copy 的 err 都要检查,hasher.Sum(nil) 后不能再往 hasher 写数据——这些点一漏,小文件测不出问题,大流量或大文件下才突然暴露。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











