我在C#中遇到以下情况:
ZipFile z1 = ZipFile.Read("f1.zip");
ZipFile z2 = ZipFile.Read("f2.zip");
MemoryStream ms1 = new MemoryStream();
MemoryStream ms2 = new MemoryStream()
ZipEntry zipentry1 = zip1["f1.dll"];
ZipEntry zipentry1 = zip2["f2.dll"];
zipentry1.Extract(ms1);
zipentry2.Extract(ms2);
byte[] b1 = new byte[ms1.Length];
byte[] b2 = new byte[ms2.Length];
ms1.Seek(0, SeekOrigin.Begin);
ms2.Seek(0, SeekOrigin.Begin);
我在这里做的是打开2个zip文件f1.zip和f2.zip。然后我在其中提取2个文件(分别在f1.zip和f2.zip中的f1.txt和f2.txt)到MemoryStream对象上。我现在想比较文件,看看它们是否相同。我有两种方法:
1)逐字节读取存储器流并进行比较。 为此,我会使用
ms1.BeginRead(b1, 0, (int) ms1.Length, null, null);
ms2.BeginRead(b2, 0, (int) ms2.Length, null, null);
然后运行for循环并比较b1和b2中的每个字节。
2)获取两个内存流的字符串值,然后进行字符串比较。为此,我会使用
string str1 = Encoding.UTF8.GetString(ms1.GetBuffer(), 0, (int)ms1.Length);
string str2 = Encoding.UTF8.GetString(ms2.GetBuffer(), 0, (int)ms2.Length);
然后做一个简单的字符串比较。
现在,我知道逐字节比较将始终给我一个正确的结果。但问题是,我需要花费很多时间才能为成千上万的文件做这件事。这就是为什么我在考虑字符串比较方法,它寻找文件是否相等或不快。但我不确定字符串比较是否会给我正确的结果,因为文件是dll或媒体文件等,并且肯定会包含特殊字符。
有人能告诉我字符串比较法是否能正常工作?
提前致谢。
P.S。 :我正在使用DotNetLibrary。
答案 0 :(得分:2)
此问题的基线是比较数组的本机方式:Enumerable.SequenceEqual
。你应该使用它,除非你有充分的理由不这样做。
如果您关心速度,可以尝试p / inv调用memcmp
中的msvcrt.dll
并比较那样的字节数组。我发现很难想象可以被打败。显然,如果两个字节数组的长度相同,那么首先要对长度进行比较,然后只调用memcmp
。
p / invoke如下所示:
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(byte[] lhs, byte[] rhs, UIntPtr count);
但是如果你真的关心速度,那么你应该只考虑这个问题,纯粹的托管替代方案对你来说太慢了。所以,做一些时间来确保你没有过早优化。好吧,甚至要确保你都在优化。
如果快速转换为string
,我会感到非常惊讶。我希望它会很慢。事实上,我希望你的代码失败,因为你的字节数组没有理由是有效的UTF-8。忘了你曾经有过这个想法!
答案 1 :(得分:2)
比较两个文件中的ZipEntry.Crc
和ZipEntry.UncompressedSize
,如果它们匹配解压缩,则仅并进行字节比较。如果两个文件相同,则它们的CRC和大小也是相同的。这种策略可以节省大量的CPU周期。
ZipEntry zipentry1 = zip1["f1.dll"];
ZipEntry zipentry2 = zip2["f2.dll"];
if (zipentry1.Crc == zipentry2.Crc && zipentry1.UncompressedSize == zipentry2.UncompressedSize)
{
// uncompress
zipentry1.Extract(ms1);
zipentry2.Extract(ms2);
byte[] b1 = new byte[ms1.Length];
byte[] b2 = new byte[ms2.Length];
ms1.Seek(0, SeekOrigin.Begin);
ms2.Seek(0, SeekOrigin.Begin);
ms1.BeginRead(b1, 0, (int) ms1.Length, null, null);
ms2.BeginRead(b2, 0, (int) ms2.Length, null, null);
// perform a byte comparison
if (Enumerable.SequenceEqual(b1, b2)) // or a simple for loop
{
// files are the same
}
else
{
// files are different
}
}
else
{
// files are different
}