我目前遇到的问题是必须散列会导致太多内存压力的文件,而我正试图找出是否可以使用文件流动态创建散列。
在研究可能性时,我决定编写一个快速的小测试,并确保MD5的ComputeHash在接受字符串和流的方法调用之间返回相同的哈希值。
let CreateMD5HashFromString (value: string) =
Convert.ToBase64String(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(value)))
let CreateMD5HashFromStream (value: Stream) =
Convert.ToBase64String(MD5.Create().ComputeHash(value))
我正在使用以下单元测试来测试呼叫:
[<TestMethod>]
member this.``CreateMD5Hash is the same between a string and a file stream`` () =
let sampleText = File.ReadAllText("Sample.txt")
let textMD5 = Security.CreateMD5HashFromString(sampleText);
let streamMD5 = Security.CreateMD5HashFromStream(File.OpenRead("Sample.txt"))
Assert.AreEqual(textMD5, streamMD5)
正在阅读一个小样本文件进行测试。此测试失败,因为生成的哈希值不同。对我来说这似乎不正确,但不完全确定。有谁知道这些应该是否相同?
另外,第二个问题,我是通过使用ComputeHash的流重载来保存自己的内存问题还是在散列之前加载整个流?我试图解散相关的.NET程序集,但是试图找出HashCore在引擎盖下做的事情就迷失了。
答案 0 :(得分:3)
实际上非常简单:你不能假设文本等于它的底层二进制表示。
在创建且 < p>
public static void Main(string[] args)
{
System.IO.File.WriteAllBytes("test", System.Text.Encoding.ASCII.GetBytes("test string"));
var inputString = System.IO.File.ReadAllText("test");
var inputBytes = System.IO.File.ReadAllBytes("test");
var inputStream = new System.IO.FileStream("test", System.IO.FileMode.OpenOrCreate);
var stringHash = Convert.ToBase64String(System.Security.Cryptography.MD5.Create().ComputeHash(System.Text.Encoding.ASCII.GetBytes(inputString)));
var streamHash = Convert.ToBase64String(System.Security.Cryptography.MD5.Create().ComputeHash(inputStream));
var bytesHash = Convert.ToBase64String(System.Security.Cryptography.MD5.Create().ComputeHash(inputBytes));
Console.WriteLine("String hash: {0}", stringHash);
Console.WriteLine("Stream hash: {0}", streamHash);
Console.WriteLine("Bytes hash: {0}", streamHash);
Console.WriteLine("\nMD5s {0}", stringHash == streamHash && streamHash == bytesHash ? "match" : "don't match");
}
带输出
String hash: b421md6Yb6t6IWJbeRZYnA==
Stream hash: b421md6Yb6t6IWJbeRZYnA==
Bytes hash: b421md6Yb6t6IWJbeRZYnA==
MD5s match
但是,这仅在假设磁盘上的文件是纯ASCII时才有效。在任何其他情况下都有零保证。例如,许多非ASCII文件以BOM(字节顺序标记)开始,以表示编码类型。这将在二进制字节数组哈希中表示,但不在内存中的字符串哈希中表示。 UTF-8和unicode通常可以为同一个字符串提供十几种不同的表示形式 - 当将string
对象加载到与磁盘上不同的表示形式时,可以对字符串进行规范化。
答案 1 :(得分:2)
我认为关键问题是,源文件中使用了什么编码?
如果使用Encoding.ASCII.GetBytes
获得的字节数组包含与Stream
相同的字节,则哈希值将相同,但只有当您使用包含相同编码的文件时才会出现这种情况。与GetBytes
一起使用的文件。文件中没有签名。
这与MD5功能无关,因此您可以通过检查来更轻松地测试(假设文件小于10kB - 否则您需要更大的缓冲区):
let res1 = Encoding.ASCII.GetBytes(File.ReadAllText("test.txt"))
let buffer = Array.zeroCreate 10240
let size = File.OpenRead("D:\\temp\\test.fsx").Read(buf, 0, 10240)
let res2 = buffer.[0 .. size - 1]
res1 = res2 // Are the byte arrays the same?
当我尝试运行时,我必须解决两件事:
我使用的文件是用带有签名的UTF-8 保存的,因此开头有3个字节指定编码(如果我使用{{我只有相同的字节数组} 1}}
我必须使用相同的编码保存文件(在这种情况下是ASCII,但是通常这样做可能很棘手)。或者,您可以在读取文件时指定编码,但随后可能会对无意义文本进行哈希处理。