2013-02-27 23 views
5

Tôi đang viết một bài kiểm tra đơn vị và cần so sánh tệp kết quả với tệp vàng. Cách dễ nhất để làm như vậy là gì?Trong C++, cách nhanh nhất để biết liệu hai chuỗi hoặc tệp nhị phân có khác nhau không?

Cho đến nay tôi có (đối với môi trường Linux):

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

Họ là khác nhau nếu result != 0

+2

Điều đó nghe giống như một cách hợp lý để so sánh hai tệp, vâng. –

+0

Có nhiều tùy chọn chuẩn khác nhau của 'diff' để triệt tiêu đầu ra. Sử dụng chúng, nếu bạn gọi nó thông qua 'hệ thống'. – pmr

+1

Bạn có thể sử dụng 'cmp' thay vì' diff'. –

Trả lời

16

Nếu bạn muốn có một c tinh khiết ++ giải pháp, tôi sẽ làm một cái gì đó như thế này

#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); 
} 

Nó tránh được đọc toàn bộ tập tin vào bộ nhớ, và dừng lại càng sớm càng các tập tin khác nhau (hoặc ở cuối của tập tin) . Phạm vi_equal vì std::equal không mất một cặp vòng lặp cho phạm vi thứ hai và không an toàn nếu phạm vi thứ hai ngắn hơn.

+0

Bạn có thể giải thích tại sao 'cuối cùng' bạn sử dụng một trình lặp đơn vị hóa không? OP đề cập đến các tệp nhị phân, nó có hợp lý không khi sử dụng ['std :: ios :: binary'] (http://stackoverflow.com/a/5420568/2436175)? Tái bút: Tôi sẽ lưu ý đây không phải là nhanh nhất, vì nó kiểm tra một byte tại thời điểm đó cũng cho các tệp lớn. Nhưng như một giải pháp đơn giản có vẻ tuyệt vời. – Antonio

+0

@Antonio Một std chưa được khởi tạo :: istreambuf_iterator là trình lặp kết thúc.Để thực hiện, mã giả định rằng luồng của bạn đang làm đệm (ví dụ, trong nhiều triển khai của 'std :: ifstream', luồng cơ bản được đệm). –

0

này nên làm việc:

#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; 
} 

Tôi nghi ngờ điều này là không nhanh như diff, nhưng tránh được gọi số system. Nó sẽ là đủ cho một trường hợp thử nghiệm, mặc dù.

+0

Bạn có thể muốn bao gồm 'iterator'. –

1

một cách để ngăn chặn việc đọc cả hai tệp là tính toán trước tệp vàng thành một băm, ví dụ: md5. Sau đó, bạn chỉ phải kiểm tra tệp thử nghiệm. Lưu ý, điều này có thể chậm hơn so với chỉ đọc cả hai tập tin!

Ngoài ra, hãy kiểm tra lớp của bạn - xem kích thước tệp, nếu chúng khác nhau thì các tệp khác nhau và bạn có thể tránh hoạt động đọc và so sánh dài.

0

Có thể là quá mức cần thiết nhưng bạn có thể tạo bảng băm SHA-256 bằng cách sử dụng tăng/bimap và tăng/scope_exit.

Dưới đây là một đoạn video làm thế nào để làm điều này bằng Stephan T Lavavej (giá khởi điểm 8,15): http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Advanced-STL/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-5-of-n

Đối với thông tin thêm về thuật toán: http://en.wikipedia.org/wiki/SHA-2

2

Phát triển từ DaveS's answer, và như điều đầu tiên 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 
} 

(Tôi tự hỏi nếu trước khi tua lại, file1 có thể được sử dụng để tạo ra kết thúc hiệu quả hơn của luồng rator, mà bằng cách biết chiều dài luồng, sẽ cho phép std::equal xử lý nhiều byte hơn vào thời điểm đó).

Các vấn đề liên quan