我正在尝试编写一个比较两个文件内容的函数.
我希望它在文件相同时返回1,如果不同则返回0.
ch1并ch2作为缓冲区,我曾经fgets获取我的文件的内容.
我认为eof指针有问题,但我不确定.FILE变量在命令行中给出.
PS它适用于大小低于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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:我已经通过包含你的答案改进了这个功能.但它只是比较第一个缓冲区 - >但有例外 - >我发现它停止读取文件,直到达到1A字符(附加文件).我们怎样才能让它发挥作用?
EDIT2:任务已解决(附加工作代码).感谢大家的帮助!
mtr*_*trw 19
如果你可以放弃一点速度,这是一种需要很少代码的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()));
}
Run Code Online (Sandbox Code Playgroud)
通过使用istreambuf_iterators您将缓冲区大小选择,实际读取和跟踪eof推入标准库实现.std::equal当它遇到第一个不匹配时返回,所以这不应该超过它需要的时间.
这比Linux慢cmp,但它很容易阅读.
由于您已经在堆栈上分配了数组,因此它们会被随机值填充......它们不会被清零.
其次,strcmp只会比较第一个NULL值,如果它是二进制文件,则不一定在文件的末尾.因此,您应该真正使用memcmp缓冲区.但同样,这会产生不可预测的结果,因为你的缓冲区是在堆栈上分配的,所以即使你比较相同的文件,缓冲区结束EOF可能也不一样,所以memcmp仍然会报告错误结果(即,由于缓冲区末尾的随机值超过每个相应文件的EOF,它很可能会报告文件不相同).
要解决这个问题,首先应该首先测量文件的长度,首先遍历文件并查看文件以字节为单位的时间,然后使用malloc或calloc分配您要比较的缓冲区,并重新用实际文件的内容填充这些缓冲区.然后,您应该能够对每个文件的二进制内容进行有效比较.此时,您还可以使用大于64K的文件,因为您在运行时动态分配缓冲区.
这是一个C++解决方案.这似乎是合适的,因为您的问题被标记为C++.该程序使用ifstream的是s而不是FILE*s.它还向您展示了如何在文件流上进行搜索以确定文件的大小.最后,它一次读取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;
}
Run Code Online (Sandbox Code Playgroud)