最稳妥方式是用 MD5.Create() 配合 FileStream 流式计算,避免 ReadAllBytes 导致内存溢出;比较文件需先比长度再比哈希,用 SequenceEqual 比较 byte[];MD5 仍适用于完整性校验,但推荐 SHA256;注意异常处理和线程安全。

用 MD5.Create() 计算文件哈希最稳妥
直接读整个文件进内存再算 MD5 容易爆内存,尤其处理 GB 级文件时。.NET 自带的 MD5.Create() 支持流式计算,这才是生产环境该用的方式。
常见错误是手动 File.ReadAllBytes() 后喂给 ComputeHash()——小文件凑合,大文件直接 OutOfMemoryException。
- 始终用
using var fs = File.OpenRead(path);打开文件,避免句柄泄漏 - 调用
md5.ComputeHash(fs),它内部会分块读取、更新状态,不占额外内存 - 结果是
byte[],转十六进制字符串用BitConverter.ToString(hash).Replace("-", "").ToLower()
比较两个文件是否相同:别只比大小,必须比哈希
文件大小一样 ≠ 内容一样。比如两个空文件、或两个全零的 1GB 文件,大小相同但可能属于不同来源;而某些日志文件可能末尾有毫秒级时间戳,大小差 1 字节但内容主体一致——是否“相同”取决于你的场景。
如果业务要求严格字节一致(如安装包校验、备份一致性检查),就必须比完整 MD5(或 SHA256 更安全)。
- 先快速排除:
new FileInfo(path1).Length != new FileInfo(path2).Length,长度不同直接返回 false - 长度相同再分别计算 MD5,
SequenceEqual()比较两个byte[]最准,比字符串比较快且不区分大小写 - 不要用
ToString()或==比较哈希字符串,容易因大小写或格式差异误判
MD5 在 C# 中的兼容性与替代建议
MD5.Create() 在 .NET Framework、.NET Core 2.0+、.NET 5+ 全平台可用,无兼容问题。但它已被密码学界认为不安全——不是不能用,而是不该用于签名、口令等场景。
纯文件完整性校验(比如判断下载是否损坏、同步是否漏字节)仍可放心用 MD5:速度快、碰撞概率对非攻击场景可忽略。
- 若项目已用
System.Security.Cryptography命名空间,优先考虑SHA256.Create(),性能差距极小,安全性更高 - .NET 5+ 可用静态方法
HashAlgorithm.HashData(File.OpenRead(path), HashAlgorithmName.SHA256),更简洁 - 别在多线程里复用同一个
MD5实例,它不是线程安全的;每次新建或用using包裹
实际代码里最容易漏掉的异常处理
文件路径不存在、权限不足、正被其他进程占用——这些都会让 File.OpenRead() 直接抛异常,而不是返回 null 或静默失败。
很多人只 try-catch CryptographicException,却忽略了 FileNotFoundException、UnauthorizedAccessException、IOException。
- 必须捕获
IOException及其子类,这是文件 I/O 的主异常基类 - 若函数要返回 bool 表示“是否一致”,遇到异常建议 throw 而不是吞掉——调用方需要知道为什么没比成
- 临时文件或网络路径(如 SMB)可能触发
DirectoryNotFoundException,也得覆盖
文件哈希计算看着简单,真正上线后出问题的,八成卡在路径权限、大文件内存、异常分支没覆盖这三处。










