应使用 MD5.Create() 创建哈希实例,字符串需用 Encoding.UTF8.GetBytes() 转字节,结果用 BitConverter.ToString(hash).Replace("-", "").ToLower() 格式化为32位小写十六进制字符串。

用 MD5.Create() 算字符串哈希,别用过时的 MD5CryptoServiceProvider
新版 .NET(.NET Core 2.0+ / .NET 5+)里 MD5CryptoServiceProvider 已标记为过时,直接 new 它会触发编译警告,运行时也可能在某些 AOT 场景下失败。统一走 MD5.Create() —— 它返回的是具体实现,兼容性好,且能被依赖注入容器识别。
注意字符串要先转字节:MD5 只处理字节数组,不是直接“算字符串”。编码选错(比如用 Encoding.Unicode 而非 Encoding.UTF8)会导致结果和别人不一致。
- 始终用
Encoding.UTF8.GetBytes(input),除非你明确知道对方用了别的编码 - 计算完用
BitConverter.ToString(hash).Replace("-", "").ToLower()转成小写无横线的 32 位 hex 字符串 - 别用
Convert.ToBase64String()—— 那是 base64,不是大家习惯的 MD5 十六进制格式
验证文件完整性:用 FileStream 流式读取,别把整个文件 load 到内存
大文件(几百 MB 以上)用 File.ReadAllBytes() 会瞬间吃光内存,还可能触发 OutOfMemoryException。MD5 不需要一次性加载全部内容,MD5 类支持流式更新。
- 用
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.SequentialScan)——FileOptions.SequentialScan告诉系统这是顺序读,提升大文件性能 - 缓冲区大小设为 8192(或 65536)比默认更稳,太小增加 I/O 次数,太大没明显收益
- 验证时别自己拼 hex 字符串做比较:用
SequenceEqual()比较两个byte[]更安全,避免大小写、空格等干扰
跨平台验证失败?检查换行符和 BOM
Windows 记事本保存的文本文件可能带 BOM(EF BB BF),Linux 下通常没有;同一段文本,不同编辑器保存的换行符可能是 \r\n 或 \n。这些都会让 MD5 完全不同,但错误很难察觉。
- 验证前先确认原始数据是否一致:用
xxd(Linux/macOS)或 PowerShell 的Get-Content -Encoding Byte看二进制内容 - 文本类文件建议先标准化:去掉 BOM(
Encoding.UTF8.GetPreamble().Length判断)、统一换行符(.Replace("\r\n", "\n").Replace("\r", "\n"))再哈希 - 如果只是校验配置文件或代码,优先考虑 SHA256 —— MD5 已不推荐用于安全场景,碰撞风险真实存在
为什么 MD5 实例不能复用?
MD5 对象是状态机,调用 ComputeHash() 后内部状态被重置。如果重复用同一个实例算多个字符串,第二个开始的结果是错的 —— 它其实是在上一次 hash 的末尾继续追加数据。
- 每次计算都应新建实例:
using var md5 = MD5.Create(); - 别写成单例或静态字段缓存
MD5实例 —— 看似省对象,实则埋雷 - 如果真要高频计算,可考虑
Span+HashAlgorithm.TryComputeHash()(.NET 5+),但对普通场景没必要
MD5 的坑不在算法本身,而在字节源、编码、流控制和实例生命周期这几个地方。只要数据输入一致、实例不复用、不用过时类型,结果就一定可重现。











