我将从我自己的类中定义的一些对象保存到File.(保存流数据).
这一切都很好,但我希望能够在File中存储该文件的CRC校验和.
然后,每当我的应用程序尝试打开文件时,它都可以读取内部存储的CRC值.
然后检查实际文件,如果文件的CRC与内部存储的CRC值匹配,我可以正常处理文件,否则显示错误消息,说文件无效.
我需要一些关于如何做到这一点的建议,我想我可以这样做:
问题是,只要在文件中更改了单个数据字节,就会导致CRC校验和完全不同 - 正如预期的那样.
Cod*_*aos 10
我通常更喜欢CRC从检查中排除的方法.但如果由于某种原因这是不可能的,那么有一个解决方法:
您需要保留8个字节,4个用于CRC,4个用于补偿数据.首先使用某个虚拟值填充保留字节(比如说0x00).然后将CRC计算为前4个字节,最后更改其他4个字节,以使文件的CRC保持不变.
有关如何执行此计算的详细信息:反转CRC32
我实际上在我的一个项目中使用了它:
我正在设计一个基于zip的文件格式.存档中的第一个文件以未压缩的形式存储,并用作头文件.这也意味着它存储在文件中的固定偏移处.到目前为止相当标准,类似于例如ePub.
现在我决定在标题中包含sha1哈希,为每个文件提供基于Id的唯一内容和完整性检查.由于标头和sha1散列位于文件中的已知偏移处,因此在散列时屏蔽它是微不足道的.所以我输入一个虚拟哈希并创建zip文件,然后散列文件并填入真正的哈希.
但现在有一个问题:Zip存储所有包含文件的CRC.而且不仅在sha1-hashing时容易屏蔽的一个地方,而且在文件末尾附近有可变偏移的第二个地方.所以我决定使用CRC伪装,所以我得到了强大的哈希值,zip获得了有效的CRC32.
由于我已经伪造了最终文件的CRC,我决定伪造原始头文件也不会受到影响.因此,此格式的所有文件现在都以具有CRC的头文件开头0xD1CE0DD5.
简单地说,您需要从校验和计算中排除用于存储校验和的字节.
将校验和写为文件中的最后一项.除校验和外,根据文件内容计算它.当您来读取文件时,根据校验和之前的内容计算校验和.或者您可以将校验和写为具有随机访问权限的文件的第一个字节.只要你知道它在哪里.
将CRC存储为文件本身的一部分,但不包括CRC计算中的数据.如果在将CRC字段传递给CRC函数之前,有某种固定的标头将CRC字段归零.如果没有,只需将它附加到文件的末尾,并将除最后4个字节之外的所有内容传递到CRC函数中.
或者,如果文件存储在NTFS驱动器上而您不需要将它们传输到另一台计算机,则可以使用NTFS备用数据流来存储CRC.基本上你打开文件,ADS名称用冒号(如C:\file.txt:CRC)分隔文件名.Windows在内部处理差异,因此您可以使用普通的TFileStream函数来操作它们.
备用数据流与标准文件流分开存储,因此打开或修改C:\file.txt不会影响它.
所以,代码看起来像这样:
procedure UpdateCRC(const aFileName: string);
var
FileStream, ADSStream: TStream;
CRC: LongWord;
begin
FileStream := TFileStream.Create(aFileName, fmOpenRead);
try
CRC := CrcOf(FileStream);
finally
FileStream.Free;
end;
ADSStream := TFileStream.Create(aFileName + ':CRC', fmCreate);
try
ADSStream.WriteBuffer(CRC, SizeOf(CRC));
finally
ADSStream.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
如果需要查找附加到文件的所有备用数据流(可以有多个),可以使用BackupRead 迭代它们.Internet Explorer使用ADS支持"此文件已从Internet下载.您确定要打开它吗?" 提示.