SHA256校验最稳妥但须用二进制流读取,CRC32仅适用于非安全场景的快速校验;比对哈希需标准化格式,大文件必须流式处理。

SHA256校验文件完整性最稳妥,但需注意字节流读取方式
SHA256 是当前推荐的文件完整性校验方式,抗碰撞能力强,适合防范恶意篡改。关键不是调用 SHA256.Create() 就完事,而是必须以**只读、二进制、不跳过 BOM 或换行处理**的方式打开文件——否则同一文件在不同编码或编辑器下可能算出不同哈希。
常见错误:用 File.ReadAllText() 读取后再转 Encoding.UTF8.GetBytes(),这会破坏原始字节(比如自动去掉 BOM、转换 CRLF/LF、替换不可见控制符)。
- 始终用
File.OpenRead(path)或new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read) - 避免任何字符串解码/编码环节;SHA256 输入必须是原始字节流
- 校验前确认文件未被其他进程锁定(否则
IOException或读取不全)
using (var fs = File.OpenRead("data.bin"))
using (var sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(fs);
string hashHex = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
CRC32适合快速校验但不能防篡改
CRC32 计算快、结果短(4 字节),常用于网络传输或本地缓存一致性检查,但它**不是密码学哈希**,极易被构造出相同 CRC 的不同内容,不能用于安全场景下的防篡改验证。
如果你只是想检测意外损坏(如磁盘坏道、传输丢包),且对性能敏感(比如每秒校验成百个 MB 级文件),CRC32 可行;但一旦涉及权限、签名、分发包验证,必须换 SHA256 或更高强度算法。
- .NET 标准库不内置 CRC32,需手动实现或引用
System.IO.Hashing(.NET 6+)或第三方包如Zlib.Portable - 注意字节序:多数实现默认小端,但某些硬件 CRC 单元用大端,校验值需统一
- 空文件的 CRC32 值是
0x00000000,而 SHA256 是固定 64 字符串,这点在日志或配置中容易混淆
比对哈希值时必须忽略大小写和分隔符
用户手输、API 返回、配置文件里存的 SHA256 值,格式五花八门:sha256: a1b2c3...、A1B2C3... 、带空格或冒号、甚至混着 Base64。直接 .Equals() 会失败。
- 标准化步骤:去空格 → 去除前缀(如
sha256:)→ 转小写 → 验证长度是否为 64 - 用
string.Equals(h1, h2, StringComparison.OrdinalIgnoreCase)比==更安全 - 不要用
Convert.ToBase64String()存哈希——它把 32 字节变成 44 字符,反而增加解析负担;十六进制字符串更通用
大文件校验要流式处理,别一次性 LoadAll
对几百 MB 或 GB 级文件,用 File.ReadAllBytes() 会瞬间吃光内存并触发 GC 压力,还可能抛 OutOfMemoryException。SHA256 和 CRC32 都支持增量计算。
- 所有
HashAlgorithm子类(包括SHA256)都提供TransformBlock()和TransformFinalBlock() - 推荐缓冲区大小:8192 或 65536 字节(太小增加调用开销,太大无益)
- 记得在最后调用
HashFinal()获取结果,否则返回的是初始状态哈希(全零)
真正容易被忽略的是:校验逻辑上线后,没人再看日志里“文件读取耗时 2.3s”这种信息——但当某次部署因 SSD 降速导致 CRC32 计算延迟突增 10 倍,下游超时熔断,问题根源就藏在这段看似无害的流式读取里。









