大文件必须用os.open + io.copy,不可用os.readfile;后者会一次性加载全部内容致oom,前者自动32kb分块、内存恒定且错误清晰。

大文件必须用 os.Open + io.Copy,别碰 os.ReadFile
几百 MB 以上的文件调用 os.ReadFile 会直接 OOM,Go 不做任何分块或流控——它真的一次性把整个文件塞进内存。而 io.Copy 底层自动按约 32KB 分块读取,内存占用恒定,且错误传播清晰。
-
os.Open后务必defer f.Close(),否则 fd 泄露,Linux 下很快触发too many open files - 别写
os.Open(file, os.O_RDONLY):默认就是只读,加 flag 反而可能引入非预期行为(比如os.O_SYNC拖慢速度) - 符号链接会被自动跟随;若需校验链接文件本身(而非目标内容),得先
os.Lstat判断类型
md5.New() 和 md5.Sum() 别混用,语义完全不同
md5.Sum([]byte(s)) 是一次性快算,返回值是结构体 md5.Sum(底层 [16]byte),只适合短文本、URL、配置键这类已加载到内存的小数据;md5.New() 返回的是 hash.Hash 接口,支持流式累积写入,专为文件、HTTP body 等设计。
- 误把
md5.New().Sum(nil)当作md5.Sum()用:前者返回[]byte,后者返回结构体,打印方式不同 -
md5.Sum([]byte("hello"))直接fmt.Printf("%x", sum)就行;但h := md5.New(); io.Copy(h, f); fmt.Printf("%x", h.Sum(nil)[:])才对 - 千万别写
h.Sum([]byte("x")):参数是拼接缓冲区,不是输入数据,结果会多出 "x" 的字节
结果必须转十六进制字符串,fmt.Printf("%x", ...) 最省事
h.Sum(nil) 返回的是 []byte,长度 16;md5.Sum().Sum(nil) 或直接 sum[:] 也是 []byte。它们都不是字符串,也不是可读的 hex 串。
- 别用
string(hash[:]):含不可见字节,还可能 panic(越界) - 别用
fmt.Println(hash):输出类似{[187 242 109 ...]},那是结构体默认格式化,不是哈希值 - 推荐统一用
fmt.Sprintf("%x", hash)—— 对md5.Sum类型和[]byte都有效,零分配、无额外依赖 - 若需 string 类型,
hex.EncodeToString(hash)更明确,但多一次内存分配
错误检查不能只看 err == nil,io.Copy 失败很常见
io.Copy 在磁盘满、权限不足、路径不存在、文件被删等场景下会提前返回 error,但很多人只检查是否为 nil,没处理具体错误类型,导致 MD5 看似“算出来了”,实则是部分数据的哈希值。
- 空文件能正常计算:
md5.Sum([]byte(""))对应d41d8cd98f00b204e9800998ecf8427e,无需特殊判断 - 常见错误:
permission denied、read xxx: is a directory、no such file or directory,都来自系统调用,不是crypto/md5的问题 - 别忽略
io.Copy的第二个返回值:n, err := io.Copy(h, f)中的err必须显式检查
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











