C#如何用LINQ表达式实现支持多偏移及任意偏移的文件签名校验
实现方案
第一步:属性调整
首先将原有的单个OffSet属性替换为int[] AllowedOffsets,约定值为-1代表允许签名出现在文件任意位置,示例配置如下:
- 仅允许偏移0:
AllowedOffsets = new[] { 0 } - 允许偏移0和4:
AllowedOffsets = new[] { 0, 4 } - 允许任意偏移:
AllowedOffsets = new[] { -1 }
第二步:核心逻辑改造
修改后的Verify方法如下:
public FileTypeVerifyResult Verify(Stream stream) { stream.Position = 0; byte[] allReadBytes; // 非任意偏移场景:仅读取需要的最大长度,减少内存占用 if (!AllowedOffsets.Contains(-1)) { var maxOffset = AllowedOffsets.Max(); var maxSignatureLength = Signatures.Max(s => s.Length); var needReadLength = maxOffset + maxSignatureLength; // 流长度不足直接返回不匹配 if (stream.Length < needReadLength) { return new FileTypeVerifyResult { Name = Name, Description = Description, IsVerified = false }; } using var reader = new BinaryReader(stream); allReadBytes = reader.ReadBytes(needReadLength); } // 任意偏移场景:读取全流字节(大文件建议改用滑动窗口匹配,避免内存溢出) else { using var ms = new MemoryStream(); stream.CopyTo(ms); allReadBytes = ms.ToArray(); } return new FileTypeVerifyResult { Name = Name, Description = Description, IsVerified = Signatures.Any(signature => { // 任意偏移匹配逻辑 if (AllowedOffsets.Contains(-1)) { if (allReadBytes.Length < signature.Length) return false; // 遍历所有可能的起始位置匹配 for (int i = 0; i <= allReadBytes.Length - signature.Length; i++) { var match = true; for (int j = 0; j < signature.Length; j++) { if (allReadBytes[i + j] != signature[j]) { match = false; break; } } if (match) return true; } return false; } // 固定偏移列表匹配逻辑 return AllowedOffsets.Any(offset => { if (offset + signature.Length > allReadBytes.Length) return false; return allReadBytes.Skip(offset).Take(signature.Length).SequenceEqual(signature); }); }) }; }
可选优化点
- 处理GB级以上大文件时,任意偏移的逻辑不要直接读取全流,可以改用滑动窗口逐段匹配,降低内存占用
- 提前对
AllowedOffsets做去重、非法值过滤(除-1外不允许负数),减少不必要的比对次数 - 短签名的任意偏移匹配可以改用KMP等字符串匹配算法,提升匹配效率
内容的提问来源于stack exchange,提问作者sirzento
相关产品推荐
相关产品推荐

