判断两个字符串或二进制文件是否不同的最快方法是什么?

What's the fastest way to tell whether two strings or binary files are different?

提问人:Victor Lyuboslavsky 提问时间:2/28/2013 最后编辑:Abderrahmene Rayene MihoubVictor Lyuboslavsky 更新时间:11/14/2023 访问量:14358

问:

我正在编写单元测试,需要将结果文件与黄金文件进行比较。最简单的方法是什么?

到目前为止,我有(对于Linux环境):

int result = system("diff file1 file2");

如果 .result != 0

C++ 字符串 比较 binaryFiles

评论

2赞 Mats Petersson 2/28/2013
这听起来像是比较两个文件的合理方法,是的。
0赞 pmr 2/28/2013
有多种标准选项可以抑制输出。使用它们,如果你通过 .diffsystem
2赞 n. m. could be an AI 2/28/2013
您可以使用 代替 .cmpdiff
1赞 chrisaycock 2/28/2013
绝对最快的,如果这些是大文件,可以检查它们的长度是否相同,然后它们并调用 .mmap()memcmp()

答:

1赞 pmr 2/28/2013 #1

这应该有效:

#include <string>
#include <fstream>
#include <streambuf>
#include <iterator>


bool equal_files(const std::string& a, const std::string& b) {
  std::ifstream stream{a};
  std::string file1{std::istreambuf_iterator<char>(stream),
                    std::istreambuf_iterator<char>()};
  
  stream = std::ifstream{b};
  std::string file2{std::istreambuf_iterator<char>(stream),
                    std::istreambuf_iterator<char>()};
  
  return file1 == file2;
}
  

我怀疑这没有 那么快,但它避免了调用。不过,对于一个测试用例来说,这应该足够了。diffsystem

评论

0赞 David Rodríguez - dribeas 2/28/2013
您可能希望包括 .iterator
2赞 gbjbaanb 2/28/2013 #2

防止读取这两个文件的一种方法是将黄金文件预先计算为哈希值,例如 MD5。然后,您只需要检查测试文件即可。请注意,这可能比仅读取两个文件慢!

或者,对检查进行分层 - 查看文件大小,如果它们不同,则文件不同,您可以避免冗长的读取和比较操作。

24赞 Dave S 2/28/2013 #3

如果你想要一个纯 c++ 解决方案,我会做这样的事情

#include <algorithm>
#include <iterator>
#include <string>
#include <fstream>

template<typename InputIterator1, typename InputIterator2>
bool
range_equal(InputIterator1 first1, InputIterator1 last1,
        InputIterator2 first2, InputIterator2 last2)
{
    while(first1 != last1 && first2 != last2)
    {
        if(*first1 != *first2) return false;
        ++first1;
        ++first2;
    }
    return (first1 == last1) && (first2 == last2);
}

bool compare_files(const std::string& filename1, const std::string& filename2)
{
    std::ifstream file1(filename1);
    std::ifstream file2(filename2);

    std::istreambuf_iterator<char> begin1(file1);
    std::istreambuf_iterator<char> begin2(file2);

    std::istreambuf_iterator<char> end;

    return range_equal(begin1, end, begin2, end);
}

它避免将整个文件读入内存,并在文件不同时(或在文件末尾)停止。range_equal因为第二个范围不需要一对迭代器,如果第二个范围较短,则不安全。std::equal

评论

0赞 Antonio 8/22/2016
您能解释为什么使用统一迭代器吗?OP 提到了二进制文件,使用 std::ios::binary 有意义吗?P.S.:我要指出的是,这不是最快的,因为它一次也会检查一个字节,以防大文件。但作为一个简单的解决方案似乎很棒。end
0赞 Dave S 8/24/2016
@Antonio 未初始化的 std::istreambuf_iterator 是结束迭代器。为了提高性能,代码假定您的流正在执行缓冲(例如,在 的许多实现中,基础流是缓冲的)。std::ifstream
1赞 Zhang 4/28/2020
md5比较怎么样?md5 的计算是否也读取了整个文件?所以它不会比直接比较文件的字节块更快吗?
0赞 Lufi 2/28/2013 #4

可能有点矫枉过正,但您可以使用 boost/bimap 和 boost/scope_exit 构建哈希表 SHA-256。

以下是 Stephan T Lavavej 的视频(从 8.15 开始): http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Advanced-STL/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-5-of-n

有关算法的详细信息,请 http://en.wikipedia.org/wiki/SHA-2

7赞 Antonio 8/23/2016 #5

DaveS 的回答开始,首先检查文件大小

#include <fstream>
#include <algorithm>

bool compare_files(const std::string& filename1, const std::string& filename2)
{
    std::ifstream file1(filename1, std::ifstream::ate | std::ifstream::binary); //open file at the end
    std::ifstream file2(filename2, std::ifstream::ate | std::ifstream::binary); //open file at the end
    const std::ifstream::pos_type fileSize = file1.tellg();

    if (fileSize != file2.tellg()) {
        return false; //different file size
    }

    file1.seekg(0); //rewind
    file2.seekg(0); //rewind

    std::istreambuf_iterator<char> begin1(file1);
    std::istreambuf_iterator<char> begin2(file2);

    return std::equal(begin1,std::istreambuf_iterator<char>(),begin2); //Second argument is end-of-range iterator
}

(我想知道在倒带之前,是否可以用来创建一个更有效的流迭代器结束,通过知道流的长度,它允许在当时处理更多的字节)。fileSizestd::equal

评论

0赞 iammilind 7/6/2018
为什么不简单地?首先存储如何帮助?if (file2.tellg() != file2.tellg())fileSize
0赞 Antonio 7/10/2018
@iammilind 感谢您指出,代码之后的后脚本中存在错误,现在应该清楚为什么我要强调文件的大小。