我正在尝试编写一个比较两个文件内容的函数。
我希望它在文件相同时返回1,如果不同则返回0。
ch1
和ch2
用作缓冲区,我使用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:任务已解决(附带工作代码)。感谢大家的帮助!
答案 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,它很可能会报告文件不相同)。
要解决此问题,首先应首先测量文件的长度,方法是首先遍历文件并查看文件的长度(以字节为单位),然后使用memcmp
或malloc
分配您要比较的缓冲区,并用实际文件的内容重新填充这些缓冲区。然后,您应该能够对每个文件的二进制内容进行有效比较。此时您还可以使用大于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)
最好使用fread
和memcmp
来避免\ 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);
}