I'm writing a unit test and need to compare a result file to a golden file. What's the easiest way to do so?
So far I have (for Linux environment):
int result = system("diff file1 file2");
They are different if result != 0
Use the command cmp to check if two files are the same byte by byte. The command cmp does not list differences like the diff command. However it is handy for a fast check of whether two files are the same or not (especially useful for binary data files).
You can use Fc.exe to compare two ASCII or binary files on a line-by-line basis. It offers several command-line options. For example, use the fc /b command to compare two binary files.
diff determines whether a file is text or binary by checking the first few bytes in the file; the exact number of bytes is system dependent, but it is typically several thousand. If every byte in that part of the file is non-null, diff considers the file to be text; otherwise it considers the file to be binary.
Electronic files are typically categorized as either binary files or text files. It could be argued that text files are also a type of binary file because, like any electronic file, they're made up of sequences of bytes. However, the two are generally considered to be different types.
If you want a pure c++ solution, I would do something like this
#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);
}
It avoids reading the entire file into memory, and stops as soon as the files are different (or at end of file). The range_equal because std::equal
doesn't take a pair of iterators for the second range, and isn't safe if the second range is shorter.
Developing from DaveS's answer, and as first thing checking file size:
#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
}
(I wonder if before rewinding, fileSize
could be used to create a more efficient end of stream iterator, which, by knowing the stream length, would allow std::equal
to process more bytes at the time).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With