哪个是比较2个文件的更好方法?

时间:2014-01-28 16:59:19

标签: c# zip zipfile

我在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。

2 个答案:

答案 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.CrcZipEntry.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
}