首先,获取两个流的哈希码并没有帮助 - 要计算哈希码,您需要读取整个内容并在读取时执行一些简单的计算。
我不确定我是否误解了它,或者这根本不是真的。这是使用流计算哈希的示例
private static byte[] ComputeHash(Stream data)
{
using HashAlgorithm algorithm = MD5.Create();
byte[] bytes = algorithm.ComputeHash(data);
data.Seek(0, SeekOrigin.Begin); //I'll use this trick so the caller won't end up with the stream in unexpected position
return bytes;
}
我用 benchmark.net 测量了这段代码,它在 900Mb 文件上分配了 384 个字节。不用说在这种情况下将整个文件加载到内存中是多么低效。
不过,这是真的
了解哈希冲突的(不太可能的)可能性很重要。为了避免这个问题,需要进行字节比较。
因此,如果哈希值不匹配,您必须执行额外的检查以确保文件 100% 不同。在这种情况下,以下是一个很好的方法。
正如您所提到的,这可以逐字节或使用缓冲区来完成。将数据读入缓冲区是个好主意,因为从 HDD 读取数据(例如读取 1kB 缓冲区)可能会更有效。
最近我不得不执行这样的检查,所以我会将这个练习的结果作为 2 个实用方法发布
private bool AreStreamsEqual(Stream stream, Stream other)
{
const int bufferSize = 2048;
if (other.Length != stream.Length)
{
return false;
}
byte[] buffer = new byte[bufferSize];
byte[] otherBuffer = new byte[bufferSize];
while ((_ = stream.Read(buffer, 0, buffer.Length)) > 0)
{
var _ = other.Read(otherBuffer, 0, otherBuffer.Length);
if (!otherBuffer.SequenceEqual(buffer))
{
stream.Seek(0, SeekOrigin.Begin);
other.Seek(0, SeekOrigin.Begin);
return false;
}
}
stream.Seek(0, SeekOrigin.Begin);
other.Seek(0, SeekOrigin.Begin);
return true;
}
private bool IsStreamEuqalToByteArray(byte[] contents, Stream stream)
{
const int bufferSize = 2048;
var i = 0;
if (contents.Length != stream.Length)
{
return false;
}
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
var contentsBuffer = contents
.Skip(i * bufferSize)
.Take(bytesRead)
.ToArray();
if (!contentsBuffer.SequenceEqual(buffer))
{
stream.Seek(0, SeekOrigin.Begin);
return false;
}
}
stream.Seek(0, SeekOrigin.Begin);
return true;
}