【问题标题】:Comparing two files in C# [duplicate]比较 C# 中的两个文件 [重复]
【发布时间】:2011-10-28 15:21:32
【问题描述】:

我想在 C# 中比较两个文件,看看它们是否不同。它们具有相同的文件名,并且在不同时它们的大小完全相同。我只是想知道是否有一种快速的方法可以做到这一点,而无需手动进入并读取文件。

谢谢

【问题讨论】:

  • 干杯,伙计们,很多很好的答案。我可能会使用逐字节比较。我将更详细地解释我的情况:我每 5 分钟从一个站点下载文件,并检查该文件是否与之前下载的文件不同。每天一次,当我停止下载文件时,它会有所不同。由于大多数时候比较是相同的,我认为逐字节比较是最好的。再次感谢!
  • 对此有很多意见,Toz。请务必阅读 cmets 以确保您正在做最适合您的用例的事情。祝你好运!
  • 早点了解用例会很有帮助。无论如何..您可能会查看 ETag HTTP 标头。让网络服务器完成所有工作。
  • @Boo:在 那些 点上你是 100% 正确的。

标签: c# .net file compare


【解决方案1】:

根据你想要走多远,你可以看看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);
}

【讨论】:

  • 如果文件只更改了一个字符,这将不起作用。流长度相同,但内容不同。这是无效的!
  • 这实际上是从微软的网站上提取的。它进行相等比较、长度比较和逐字节比较。我想你可能对这个有误。
  • 对不起,我不想听起来粗鲁:-) 问题是“它们具有相同的文件名,并且在不同时它们的大小完全相同”。所以这种方法容易出错。我们开发了一个版本控制系统,这种实现可能会导致 SCM 数据库发生灾难。
  • @Daniel:很抱歉恢复旧帖子,但您能解释一下代码的实际问题吗?对我来说似乎没问题,它正在检查文件大小,然后逐字节检查。单个字符差异如何逃脱检查?谢谢!
  • 代码是正确的,但您必须向下滚动才能看到逐字节比较的位。我猜丹尼尔没有向下滚动。
【解决方案2】:

我只是想知道是否有一种无需手动进入并读取文件的快速方法。

不是。

如果文件带有哈希值,您可以比较哈希值,如果它们不同,您可以得出文件不同的结论(但是,相同的哈希值并不意味着文件相同并且所以你仍然需要逐字节比较)。

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

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

【讨论】:

  • 如果你有相同的哈希值,你可以确定文件是相同的。您是对的,您需要逐字节比较文件以绝对确定(尤其是如果您的安全性取决于此)。但是像 git 这样的一些系统依赖于这样一个事实,即具有相同哈希值的两个不同文件不会出现在系统内部。当然,这一切都假设有良好的哈希值,而不是像 GetHashCode() 这样的东西。
  • @scottm:因为不相等的文件可以有相等的哈希值。这就是鸽巢原理。假设我们正在使用 md5。 md5 生成文件的 128 位哈希。因此,有 2^128 个不同的哈希值。有超过 2^128 个不同的文件。因此,由于我们将具有超过 2^128 个不同值的空间映射到具有 2^128 个值的空间,因此肯定存在冲突。哈希不是唯一的签名。
  • @Random:我提到当哈希不相等时,您可以使用哈希来得出文件不相等的结论,并且在预先计算它们时是有利的。如果它们没有预先计算,它们不会更快,如果它们相等,我们仍然必须逐字节进行。
  • @svick:当然 git 依赖于那个假设,但它很容易发生哈希冲突。这对 git 来说是个问题。
  • @Jason,我认为这是一个潜在的问题,但在实践中这不是问题。如果您知道不会有攻击者试图破坏哈希,则不必担心冲突。
【解决方案3】:

好吧,我不确定您是否可以在文件中写入时间戳。如果没有,您唯一的选择是比较文件的内容。

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

下面的代码 sn-p 展示了如何做到这一点:

    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);
    }

如果您要将一个文件与其他文件进行多次比较,您可以保存文件哈希并进行比较。对于单个比较,逐字节比较更好。您还需要在文件更改时重新计算哈希,但如果您要进行大量比较(不止一次),我建议使用哈希方法。

【讨论】:

  • 不!如果哈希值相等,您 STILL 必须逐字节比较。如果散列不相等,则逐字节执行会更快,因为它可以在第一个不相等的字节对上提前终止,但散列必须贯穿整个文件!啊!
  • 如果你有两个文件可用,我认为计算两者的哈希值实际上比直接比较它们要慢。
  • @svick:是的。逐字节可以提前终止,散列仍然像逐字节一样读取所有内容,如果散列相等,我们必须逐字节读取。
  • @Jason:这个想法是将文件哈希存储在任何地方并利用它。是的,当然,如果只计算一次,逐字节比较会更好。
  • @Daniel Peñalba:但是当哈希值等于 100% 确定文件相等时,您仍然必须逐字节进行。
【解决方案4】:

如果文件名相同,文件大小相同,那么,不,如果不检查内容,就无法知道它们是否有不同的内容。

【讨论】:

  • 我支持 Jason:请在投反对票时发表评论。
  • 这个答案虽然简洁,但(目前)是该线程中唯一的其他正确答案。它不应该被否决。
【解决方案5】:

将文件读入流,然后散列流。这应该会给你一个可靠的比较结果。

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; 
        }
    }

【讨论】:

    【解决方案6】:

    如果它们不是经过编译的文件,则使用 KDiff 或 WinMerge 等差异工具。它将突出显示它们是否不同。

    http://kdiff3.sourceforge.net/

    http://winmerge.org/

    【讨论】:

    • 问题是关于如何以编程方式比较 .net 中的两个文件。提问者正在用 C# 编写代码,需要他编写的程序来比较两个文件。他可能对 shellout 或 GUI 工具不感兴趣。
    【解决方案7】:

    通过一个 MD5 散列器传递每个文件流并比较散列值。

    【讨论】:

    • 但是如果哈希值相等,您仍然必须手动读取文件并逐字节比较以得出它们实际上相等的结论。这不是更少的工作。您无法避免需要逐字节比较。
    • 更少的编程工作。 CPU 还没有感知(尚未),所以谁在乎它是否需要做任何额外的工作。现代 CPU 足够快,除非您在短时间内完成大量工作,否则您不会注意到额外的工作。但 OP 并未表明情况如此。
    • 您没有注意:如果哈希值相等,您 STILL 必须进行逐字节比较。使用散列的工作量并不小,它是MORE的工作,因为你必须编写逐字节比较和代码来使用散列算法,以及在使用散列算法时使用逐字节的逻辑哈希值相等。
    • 不,这意味着它们具有相同的哈希值。它并不“意味着文件是相同的。”
    • 十六进制代码 d131dd02c5e6eec4693d9a0698aff95c 2fcab58712467eab4004583eb8fb7f89 55ad340609f4b30283e488832571415a 085125e8f7cdc99fd91dbdf280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e2b487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080a80d1e c69821bcb6a8839396f9652b6ff72a70d131dd02c5e6eec4693d9a0698aff95c 2fcab50712467eab4004583eb8fb7f89 55ad340609f4b30283e4888325f1415a 085125e8f7cdc99fd91dbd7280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e23487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080280d1e c69821bcb6a8839396f965ab6ff72a70 具有相同的 md5 哈希值。它们不相等。
    猜你喜欢
    • 1970-01-01
    • 2011-03-11
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多