应用层主动校验不可替代:ntfs/refs完整性流默认关闭且保护有限,btrfs/zfs端到端校验不覆盖跨设备复制等场景;sha-256是长期存储最稳妥哈希算法;需异步分块校验、集中存储带签名的哈希快照并隔离故障域。

为什么不能只靠文件系统自带的校验
NTFS、ReFS 确实支持可选的完整性流(如 fsutil behavior set disablelastaccess 1 配合 fsutil integrity),但默认关闭,且仅保护元数据或特定启用的文件;Linux 的 Btrfs/ZFS 虽有端到端校验,但 .NET 应用通常不直接依赖底层——一旦文件被意外覆盖、静默写入错误(如坏扇区未报错但返回了脏数据)、或跨设备复制时内存位翻转,这些机制可能漏检。真正可控的校验必须由应用层主动发起。
ComputeHash 选哪个算法才适合长期存储
SHA-256 是当前最稳妥的选择:抗碰撞性强、硬件加速普及、输出长度适中(32 字节),比 MD5/SHA-1 安全,又比 SHA-512 在小文件场景下无明显优势。避免用 MD5CryptoServiceProvider(已标记为过时)或 SHA1Managed(已被弃用且易碰撞)。
实操建议:
- 用
using var hash = SHA256.Create();获取实例,它在 Windows 上自动使用BCryptHash硬件加速 - 对大文件(>100MB)分块读取,避免
File.ReadAllBytes导致内存暴涨:using var fs = File.OpenRead(path); using var hash = SHA256.Create(); hash.ComputeHash(fs); // 内部已优化流式处理
- 校验值存为 Base64(而非十六进制)更省空间:
Convert.ToBase64String(hash.ComputeHash(fs))
如何设计定期校验任务不阻塞主线程
后台服务中硬编码 Task.Delay + while(true) 容易泄漏或失控;ASP.NET Core 中用 IHostedService 更可靠,但注意:校验是 I/O 密集型,别用 Task.Run 包裹同步 IO(如 File.OpenRead),会浪费线程池资源。
正确做法:
- 用
FileStream的异步方法:await fs.ReadAsync(buffer, token),配合MemoryPool<byte>.Shared.Rent()</byte>复用缓冲区 - 限制并发数(比如最多 3 个文件同时校验),防止磁盘吞吐打满:
SemaphoreSlim控制 - 校验失败时记录完整路径、期望哈希、实际哈希、时间戳到本地日志文件,**不要抛出异常中断整个任务**
校验结果怎么存才不怕自己损坏
把哈希值存在同目录下的 .sha256 文件里?风险很高——同一磁盘故障可能同时毁掉原文件和校验文件。更可靠的方式:
- 集中存到独立位置:如网络共享卷、另一台机器的 SQLite 数据库(含
file_path TEXT UNIQUE,hash_b64 TEXT,last_checked DATETIME) - 为校验元数据本身加签名:用非对称密钥(如
RSA.Create().SignData)对哈希列表签名,防篡改 - 至少保留两份校验快照:当前值 + 上次成功值,对比差异能发现“缓慢腐化”(如 SSD 逐渐退化导致偶发位错误)
静默损坏最难缠的地方在于它不报错、不中断流程,只悄悄改数据——所以校验逻辑本身必须足够轻量、可审计、且校验依据不能和被校验物共享物理故障域。









