filestream逐字节比对是最直接的文件一致性判断方式:先比长度,再用缓冲区读取并逐字节比对,遇差异立即退出;需注意offset计算、大文件long类型、dispose释放及避免文本编码干扰。

用 FileStream 逐字节比对是最直接的方式
如果只是判断两个文件是否完全相同,不需要输出差异位置或生成 patch,直接用 FileStream 配合 ReadByte() 或缓冲区读取即可。关键点在于:必须确保文件长度一致,否则提前返回不等;长度相同时再逐块比对,避免一次性加载大文件进内存。
- 先用
FileInfo.Length比较大小,不等直接返回false - 使用固定大小缓冲区(如 8192 字节)读取,用
SequenceEqual()或手动循环比对字节数组 - 遇到第一个不匹配的字节就立即退出,不要继续读——这对 GB 级文件影响显著
- 注意
FileStream要用FileAccess.Read和FileShare.Read,避免被其他进程锁住
要定位差异偏移量就得自己维护读取位置
标准库没有现成的“返回第一个不同字节索引”的 API,所以得边读边计数。常见错误是只比对内容、忽略 offset 计算,导致报告的位置不准。
- 每次读取
buffer.Length字节后,用for循环检查每个buffer[i],当前全局 offset = 已读总字节数 +i - 不要用
Stream.Position做判断依据——它在异步或某些封装流中可能不可靠 - 如果文件极大(>4GB),记得用
long类型存 offset,别用int - 遇到 EOF 但另一文件还有数据?说明长度已不一致,此时 offset 就是较短文件的
Length
生成二进制 patch 需要类似 bsdiff 的算法逻辑
.NET 标准库不提供二进制差分(binary diff)算法实现,System.Diff 仅面向文本。真要生成 patch,得引入外部思路或轻量级实现。
- 简单场景可用“分块哈希 + 差异标记”:把文件切为固定块(如 64KB),计算每块 SHA256,找出哪些块相同/不同,再只保存不同块的原始字节 —— 这不是标准 bsdiff,但适合内部工具快速落地
- 若需兼容
bspatch,建议调用原生bsdiff.exe通过Process.Start,而不是纯 C# 实现(算法复杂且易出边界错误) - 注意 patch 文件本身也要有头部描述:源文件 size、目标文件 size、块数量、每个块的操作类型(copy/skip/insert)
- 别忘了处理小文件(
跨平台和大文件要注意 MemoryMappedFile 的陷阱
有人想用内存映射加速比对,但 Windows 和 Linux 对 MemoryMappedFile 的行为有细微差别,尤其在超大文件(>2GB)和稀疏文件上。
- Linux 下 mmap 失败时抛
IOException,Windows 可能静默失败或返回空视图 —— 务必检查MapViewSize是否等于预期 - 32 位进程中,单次映射不能超过 2GB,即使文件更大也得循环映射多个区域
- 映射后仍要按页对齐访问(通常 4KB),否则某些硬件会触发异常;别直接对指针做
++跨页操作 - 比对完成后必须显式调用
Dispose(),否则在容器环境里可能引发句柄泄漏
实际做二进制 diff 时,最常被跳过的其实是文件打开权限和编码无关性验证——二进制文件根本不存在编码,但有人误用 StreamReader 去读,结果一上来就报 UTF8Encoding 异常。盯紧 FileStream,其他都绕开。










