【问题标题】:Comparing two files in C++在 C++ 中比较两个文件
【发布时间】:2012-02-27 12:02:29
【问题描述】:

我有一个比较两个文件的函数,看看它们是否相同。它逐字节读取文件并检查它们是否相同。
我现在遇到的问题是,对于大文件,此功能需要很长时间。

检查文件是否相同的更好、更快的方法是什么?

【问题讨论】:

  • @Yavar -- 比较文件需要读取所有数据以及单个指令比较。散列数据需要读取所有数据以及更复杂的数学运算。我错过了什么表明哈希方法会更快(除非您假设哈希是预先存在的)?我一定遗漏了一些东西,因为有几位海报建议使用哈希。我相信除非哈希预先存在,否则这比 memcmp 慢。
  • 绝对@mah +1 为您的评论。
  • 在检查通过网络下载的文件是否在传输过程中损坏时,散列是一个很好的解决方案。您在服务器上生成一个哈希值,并将其与客户端下载文件的哈希值进行比较。在通过网络传输文件的情况下,这很有意义。比较磁盘上漂亮的两个文件是没有意义的。
  • Hashinh 如果您有 3 个以上的文件并且您正在寻找相同的文件对。

标签: c++ windows file


【解决方案1】:

当您的文件不同时,它们的大小可能相同吗?如果不是,您可以立即确定文件大小(fseek 到最后,ftell 确定位置),如果它们不同,那么您无需比较数据就知道它们不一样。如果大小相同,记得fseek回到开头。

如果您将文件读入大型内存缓冲区并使用 memcmp() 比较每个缓冲区,您将提高性能。您不必一次读取整个文件,只需设置一个较大的缓冲区大小并从每个文件中读取该大小的块,以便通过循环进行每次比较迭代。 memcpy 函数将对 32 位值进行操作,而不是 8 位字节。

【讨论】:

  • 我推荐这个答案。比较两个哈希值时,文件相同的概率很高。你仍然不能百分百确定。此外,由于您仍然需要从两个文件中读取数据以生成哈希...您不妨只比较您读取的每个块而不是计算哈希。
  • 如果两个文件之后都被丢弃并且没有重用哈希,那么直接比较可能是最好的。但是,使用哈希是因为它们在 CPU 和工具包级别进行了优化,并且存储哈希以供重复使用可以节省大量的处理时间。
  • @PhilHannent:正如 mah 已经提到的,memcmp 也在 CPU 级别进行了优化(事实上,一些实现甚至会使用 CPU 的 SSE 单元并在 64+ 位上运行)。
  • 解决方案是最佳的,但使用 fseek/ftell 会让我失去理智。为什么,在 Windows 上(不是在地球上!),你不能使用 GetFileSize 来代替?
  • @seand - 是的。暂时忽略读取fgetc() 的单字节,您仍然一次只比较一个字节;您的 CPU 能够在同一条指令中比较至少四个字节,因此会增加很多不必要的开销。除此之外,调用单字节(甚至只是小缓冲区)读取而不是一个或几个大缓冲区读取意味着您必须比必要更频繁地调用库,从而增加大量额外开销。
【解决方案2】:

如果你真的想要两个文件的蛮力比较,mmaping may help。

如果您知道所阅读内容的文件结构,请阅读独特的部分,以便您快速识别它们(例如标题和相关的块/部分)。当然,在比较之前你会想得到它的基本属性。

如果您进行多重比较,则生成哈希(或其他东西)。

【讨论】:

  • 你的答案应该颠倒过来。映射是一个很好的建议,散列不是。搜索文件头是一个很好的解决方案,但仅限于适用的地方。
  • @MahmoudAl-Qudsi 但我限定了散列的适用性:“生成散列(或其他东西)如果你进行多重比较。”
  • 我很抱歉。此外,映射可用于加速散列过程,其中有一些关于页面错误的非常非常重要的警告。
  • @MahmoudAl-Qudsi 没问题。反转,并添加链接。
【解决方案3】:

以 X 大小的块读取文件。X 最大为 1-10-50 兆字节。在这些块上使用memcmp()。

【讨论】:

    【解决方案4】:

    虽然有许多使用 SHA 或 MD5 的加密散列函数示例,但对于文件比较,最好使用非加密散列,因为它会更快:

    https://en.wikipedia.org/wiki/List_of_hash_functions#Non-cryptographic_hash_functions

    FNV 散列被认为是快速满足您的需求:

    https://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash

    【讨论】:

    • 其实文件比较no hash比较快。散列需要读取+计算。比较只需要阅读。猜猜哪个更快?
    • @MahmoudAl-Qudsi 当然,您很少进行直接比较,通常情况下您可以存储哈希值以供以后再次比较。只制作一个文件的哈希值,以便在新数据到达时进行比较。
    • 同意.. OP 确实需要更具体。目前看起来他正在制作一个非常幼稚的二进制(是/否)差异程序。
    【解决方案5】:

    如果您不熟悉 google 上有关“MD5”或“SHA”算法的散列搜索。 散列是检查文件一致性的有效方法之一。 只需要找到其中一种算法的实现并检查它们;例如:

    if(md5(file1Path) == md5(file2Path))
        cout<<"Files are equal"<<endl;
    else
        cout<<"Files are not equal"<<endl;
    

    【讨论】:

    • 当然,如果您已经提前完成了哈希,哈希会更有效......但是如果您必须在运行时计算哈希,您真的相信您可以更快地生成 x 字节的哈希吗比你可以将 x 字节与 x 其他字节进行比较?
    猜你喜欢
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-13
    相关资源
    最近更新 更多