比较两个文件

时间:2011-05-28 18:28:36

标签: c++

我正在尝试编写一个比较两个文件内容的函数。

我希望它在文件相同时返回1,如果不同则返回0。

ch1ch2用作缓冲区,我使用fgets来获取文件的内容。

我认为eof指针有问题,但我不确定。 FILE变量在命令行中给出。

P.S。它适用于大小低于64KB的小文件,但不适用于较大的文件(例如700MB电影或5MB .mp3文件)。

任何想法,如何解决?

int compareFile(FILE* file_compared, FILE* file_checked)
{
    bool diff = 0;
    int N = 65536;
    char* b1 = (char*) calloc (1, N+1);
    char* b2 = (char*) calloc (1, N+1);
    size_t s1, s2;

    do {
        s1 = fread(b1, 1, N, file_compared);
        s2 = fread(b2, 1, N, file_checked);

        if (s1 != s2 || memcmp(b1, b2, s1)) {
            diff = 1;
            break;
        }
      } while (!feof(file_compared) || !feof(file_checked));

    free(b1);
    free(b2);

    if (diff) return 0;
    else return 1;
}
编辑:我已经通过包含你的答案改进了这个功能。但它只是比较第一个缓冲区 - >但有一个例外 - >我发现它停止读取文件,直到它达到1A字符(附加文件)。我们怎样才能使它发挥作用?

EDIT2:任务已解决(附带工作代码)。感谢大家的帮助!

6 个答案:

答案 0 :(得分:18)

如果你可以放弃一点速度,这是一种需要很少代码的C ++方式:

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

bool compareFiles(const std::string& p1, const std::string& p2) {
  std::ifstream f1(p1, std::ifstream::binary|std::ifstream::ate);
  std::ifstream f2(p2, std::ifstream::binary|std::ifstream::ate);

  if (f1.fail() || f2.fail()) {
    return false; //file problem
  }

  if (f1.tellg() != f2.tellg()) {
    return false; //size mismatch
  }

  //seek back to beginning and use std::equal to compare contents
  f1.seekg(0, std::ifstream::beg);
  f2.seekg(0, std::ifstream::beg);
  return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
                    std::istreambuf_iterator<char>(),
                    std::istreambuf_iterator<char>(f2.rdbuf()));
}

通过使用istreambuf_iterators,您可以将缓冲区大小选择,实际读取和eof跟踪推送到标准库实现中。 std::equal在遇到第一个不匹配时返回,因此这不应该超出它所需的时间。

这比Linux的cmp慢,但它很容易阅读。

答案 1 :(得分:9)

当文件是二进制文件时,使用memcmp而不是strcmp,因为\ 0可能显示为数据。

答案 2 :(得分:8)

由于您已经在堆栈上分配了数组,因此它们会被随机值填充......它们不会被清零。

其次,strcmp只会与第一个NULL值进行比较,如果它是二进制文件,则不一定在文件的末尾。因此,您应该在缓冲区上使用memcmp。但同样,由于你的缓冲区是在堆栈上分配的,所以这会产生不可预测的结果,所以即使你比较相同的文件,超过EOF的缓冲区的结尾可能也不一样,所以{{ 1}}仍将报告错误结果(即,由于缓冲区末尾的随机值超过每个相应文件的EOF,它很可能会报告文件不相同)。

要解决此问题,首先应首先测量文件的长度,方法是首先遍历文件并查看文件的长度(以字节为单位),然后使用memcmpmalloc分配您要比较的缓冲区,并用实际文件的内容重新填充这些缓冲区。然后,您应该能够对每个文件的二进制内容进行有效比较。此时您还可以使用大于64K的文件,因为您在运行时动态分配缓冲区。

答案 3 :(得分:8)

这是一个C ++解决方案。这似乎是合适的,因为您的问题被标记为C++。该计划使用ifstream而不是FILE*。它还向您展示了如何在文件流上进行搜索以确定文件的大小。最后,它一次读取4096个块,因此将按预期处理大型文件。

// g++ -Wall -Wextra equifile.cpp -o equifile.exe

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;

#include <fstream>
using std::ios;
using std::ifstream;

#include <exception>
using std::exception;

#include <cstring>
#include <cstdlib>
using std::exit;
using std::memcmp;

bool equalFiles(ifstream& in1, ifstream& in2);

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        cerr << "Usage: equifile.exe <file1> <file2>" << endl;
        exit(-1);
    }

    try {
        ifstream in1(argv[1], ios::binary);
        ifstream in2(argv[2], ios::binary);

        if(equalFiles(in1, in2)) {
            cout << "Files are equal" << endl;
            exit(0);
        }
        else
        {
            cout << "Files are not equal" << endl;
            exit(1);
        }

    } catch (const exception& ex) {
        cerr << ex.what() << endl;
        exit(-2);
    }

    return -3;
}

bool equalFiles(ifstream& in1, ifstream& in2)
{
    ifstream::pos_type size1, size2;

    size1 = in1.seekg(0, ifstream::end).tellg();
    in1.seekg(0, ifstream::beg);

    size2 = in2.seekg(0, ifstream::end).tellg();
    in2.seekg(0, ifstream::beg);

    if(size1 != size2)
        return false;

    static const size_t BLOCKSIZE = 4096;
    size_t remaining = size1;

    while(remaining)
    {
        char buffer1[BLOCKSIZE], buffer2[BLOCKSIZE];
        size_t size = std::min(BLOCKSIZE, remaining);

        in1.read(buffer1, size);
        in2.read(buffer2, size);

        if(0 != memcmp(buffer1, buffer2, size))
            return false;

        remaining -= size;
    }

    return true;
}

答案 4 :(得分:3)

最好使用freadmemcmp来避免\ 0字符问题。此外,!feof检查确实应该是||而不是&amp;&amp;因为一个文件比另一个文件大的可能性很小,而较小的文件可以被缓冲区大小整除..

int compareFile(FILE* f1, FILE* f2) {
  int N = 10000;
  char buf1[N];
  char buf2[N];

  do {
    size_t r1 = fread(buf1, 1, N, f1);
    size_t r2 = fread(buf2, 1, N, f2);

    if (r1 != r2 ||
        memcmp(buf1, buf2, r1)) {
      return 0;
    }
  } while (!feof(f1) || !feof(f2));

  return 1;
}

答案 5 :(得分:3)

Switch的代码对我来说很好,但如果你想要一个确切的     比较while条件和返回需要改变:

int compareFile(FILE* f1, FILE* f2) {
  int N = 10000;
  char buf1[N];
  char buf2[N];

  do {
    size_t r1 = fread(buf1, 1, N, f1);
    size_t r2 = fread(buf2, 1, N, f2);

    if (r1 != r2 ||
        memcmp(buf1, buf2, r1)) {
      return 0;  // Files are not equal
    }
  } while (!feof(f1) && !feof(f2));

  return feof(f1) && feof(f2);
}