在C#中比较两个文件

16

我想在C#中比较两个文件并查看它们是否不同。 它们具有相同的文件名,并且当它们不同时它们的大小完全相同。 我只是想知道是否有快速的方法可以在不手动读取文件的情况下完成此操作。

谢谢


谢谢大家,回答很好。我可能会使用逐字节比较。我将更详细地解释我的情况: 我每隔5分钟从一个网站下载文件,并检查文件是否与以前下载的文件不同。当它一天内不同时,我停止下载文件。由于比较大部分时间都是相同的,所以我认为逐字节比较是最好的。再次感谢! - Toz
这个问题有很多不同的意见,Toz。一定要阅读评论,确保你为你的使用情况做出最好的选择。祝你好运! - Random
早些了解使用情况会很有帮助。无论如何,您可以查看ETag HTTP标头。让Web服务器完成所有工作。 - Sam Axe
@Boo:在那些方面,你是100%正确的。 - jason
7个回答

30

根据你想达到的目的,你可以看一下 Diff.NET

这里是一个简单的文件比较函数:

// This method accepts two strings the represent two files to 
// compare. A return value of 0 indicates that the contents of the files
// are the same. A return value of any other value indicates that the 
// files are not the same.
private bool FileCompare(string file1, string file2)
{
     int file1byte;
     int file2byte;
     FileStream fs1;
     FileStream fs2;

     // Determine if the same file was referenced two times.
     if (file1 == file2)
     {
          // Return true to indicate that the files are the same.
          return true;
     }

     // Open the two files.
     fs1 = new FileStream(file1, FileMode.Open, FileAccess.Read);
     fs2 = new FileStream(file2, FileMode.Open, FileAccess.Read);

     // Check the file sizes. If they are not the same, the files 
        // are not the same.
     if (fs1.Length != fs2.Length)
     {
          // Close the file
          fs1.Close();
          fs2.Close();

          // Return false to indicate files are different
          return false;
     }

     // Read and compare a byte from each file until either a
     // non-matching set of bytes is found or until the end of
     // file1 is reached.
     do 
     {
          // Read one byte from each file.
          file1byte = fs1.ReadByte();
          file2byte = fs2.ReadByte();
     }
     while ((file1byte == file2byte) && (file1byte != -1));

     // Close the files.
     fs1.Close();
     fs2.Close();

     // Return the success of the comparison. "file1byte" is 
     // equal to "file2byte" at this point only if the files are 
     // the same.
     return ((file1byte - file2byte) == 0);
}

2
这实际上是从微软的网站上取出的。它进行了相等比较、长度比较和逐字节比较。我认为你可能错了。 - James Johnson
4
抱歉打扰您,但您能否解释一下代码的实际问题是什么?在我看来,它检查文件大小,然后逐字节检查。一个单字符差异怎么可能逃过检查呢?谢谢! - argatxa
我会说这段代码是正确的。 - Stabledog
14
代码是正确的,但您需要向下滚动以查看逐字节比较的部分。我认为丹尼尔没有向下滚动。 - Dave Knight
在这个该死的OS X上,你看不到整个代码而且也没有滚动条来提示还有更多的代码。 - Andrei Rînea
显示剩余3条评论

18

我只是在想是否有一种快速的方法可以不必手动读取文件就能完成这项任务。

实际上没有。

如果文件已经有了哈希值,你可以比较这些哈希值。如果它们不同,那么你就可以得出这些文件不同的结论(然而,相同的哈希值并不意味着文件相同,因此你仍然需要进行逐字节比较)。

但是,哈希使用了文件中的所有字节,因此无论如何,你最终都必须逐字节读取文件。事实上,直接逐字节比较将比计算哈希快得多。这是因为哈希像逐字节比较一样读取了所有的字节,但哈希还要进行其他计算,这些计算会增加时间。此外,逐字节比较可以在第一对不相等字节时提前终止。

最后,你无法避免需要逐字节读取的需求。如果哈希值相同,并不意味着文件相同。在这种情况下,你仍然需要逐字节比较。


2
如果您有相同的哈希值,那么您可以非常确定这些文件是相同的。您是正确的,需要逐字节比较文件才能绝对确定(特别是如果您的安全性取决于此)。但是,一些系统(如git)依赖于两个具有相同哈希值的不同文件不会出现在系统中的事实。当然,这都是建立在良好哈希算法的前提下,而不是像GetHashCode()这样的东西。 - svick
2
@scottm:因为不同的文件可能具有相等的哈希值。这是鸽笼原理。假设我们使用md5。md5会生成文件的128位哈希值。因此,有2^128种不同的哈希值。有比2^128个不同的文件要多得多。因此,由于我们正在将一个具有超过2^128个不同值的空间映射到一个具有2^128个值的空间中,必须存在冲突。哈希值不是唯一的标识。 - jason
1
@Random:我提到了您可以使用哈希函数来确定文件是否不同,当哈希值不同时就意味着文件不同。如果预先计算哈希值,那么这将是一个优点。如果没有预先计算,那么速度并不会更快;如果哈希值相等,我们仍然需要逐字节比较。 - jason
1
@Jason,我认为这是一个潜在的问题,但在实践中并不是问题。如果你知道没有攻击者试图破解哈希,你就不必担心碰撞。 - svick
1
@svick:但这正是 Git 使用 SHA-1 的目的之一!它可以检测到仓库的损坏,可能是由恶意攻击者造成的。 - jason
显示剩余4条评论

4

嗯,我不确定你是否可以在文件中写入时间戳。如果不能,你的唯一替代方法是比较文件的内容。

一个简单的方法是逐字节比较文件,但如果你要多次将文件与其他文件进行比较,你可以计算文件的哈希码并进行比较。

以下代码片段展示了如何实现:

    public static string CalcHashCode(string filename)
    {
        FileStream stream = new FileStream(
            filename,
            System.IO.FileMode.Open,
            System.IO.FileAccess.Read,
            System.IO.FileShare.ReadWrite);

        try
        {
            return CalcHashCode(stream);
        }
        finally
        {
            stream.Close();
        }
    }

    public static string CalcHashCode(FileStream file)
    {
        MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();
        Byte[] hash = md5Provider.ComputeHash(file);
        return Convert.ToBase64String(hash);
    }

如果您需要多次比较文件,可以保存文件的哈希值并进行比较。但是,如果只需进行一次比较,则最好使用逐字节比较。当文件发生更改时,您还需要重新计算哈希值。但是,如果您需要进行大量比较(超过一次),建议使用哈希方法。

4
不!如果哈希值相等,仍然需要逐字节比较。而如果哈希值不相等,则直接进行逐字节比较会更快,因为它可以在第一组不相等的字节上提前终止,但哈希值必须对整个文件进行处理!唉! - jason
1
如果您两个文件都有,我认为计算它们的哈希值实际上比直接比较它们要慢。 - svick
1
@svick:是的。逐字节比较可以提前终止,哈希仍然会读取所有内容,就像逐字节比较可能一样,如果哈希相等,我们仍然必须逐字节比较。 - jason
1
@Jason:这个想法是将文件哈希存储在任何地方并利用它。当然,如果您只计算一次,则逐字节比较更好。 - Daniel Peñalba
1
@Daniel Peñalba:但是当哈希值相等时,您仍然必须逐字节进行比较,以确保文件完全相同。 - jason
显示剩余3条评论

3
如果文件名相同,文件大小相同,则无法在不检查内容的情况下知道它们是否具有不同的内容。

我和 Jason 一致:请在您点踩时发表评论。 - AllenG
这个回答虽然简洁,但(目前)是本帖唯一的其他正确答案。不应该被踩。 - jason

0

将文件读入流中,然后对流进行哈希处理。这样可以得到一个可靠的结果用于比较。

byte[] fileHash1, fileHash2;

using (SHA256Managed sha = new SHA256Managed())
{
    fileHash1 = sha.ComputeHash(streamforfile1);
    fileHash2 = sha.ComputeHash(streamforfile2);
}

for (int i = 0; (i < fileHash1.Length) && (i < fileHash2.Length); i++)
    {
        if (fileHash[i] != fileHash2[i]) 
        { 
             //files are not the same
             break; 
        }
    }

-2

这个问题是关于如何在 .net 中编程比较两个文件。提问者正在使用 C# 编写代码,并需要程序比较两个文件。他可能对 shellout 或 GUI 工具不感兴趣。 - binki

-2

将每个文件流通过MD5哈希器并比较哈希值。


1
但是如果哈希值相等,你仍然需要手动读取文件并逐字节比较才能得出它们实际上是相等的结论。这并不会减少工作量。你无法避免逐字节比较的需要。 - jason
1
你没有注意到:如果哈希值相等,你仍然需要进行逐字节比较。使用哈希值并不会减少工作量,反而会增加工作量,因为你需要编写逐字节比较的代码和使用哈希算法的代码,以及在哈希值相等时使用逐字节比较的逻辑。 - jason
1
十六进制代码 d131dd02c5e6eec4693d9a0698aff95c 2fcab58712467eab4004583eb8fb7f89 55ad340609f4b30283e488832571415a 085125e8f7cdc99fd91dbdf280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e2b487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080a80d1e c69821bcb6a8839396f9652b6ff72a70d131dd02c5e6eec4693d9a0698aff95c 2fcab50712467eab4004583eb8fb7f89 55ad340609f4b30283e4888325f1415a 085125e8f7cdc99fd91dbd7280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e23487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080280d1e c69821bcb6a8839396f965ab6ff72a70 具有相同的 MD5 哈希值。它们并不相等。 - jason
1
@L.B:同样的问题适用于任何哈希算法。任何。哈希将大空间压缩到小空间。每个哈希算法都会有碰撞,而且很多。 - jason
1
@Boo:惊人。OP想知道这些文件是否相同,而不是它们可能相同。 - jason
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接