compare different length files

These two files are identical up to first oef, but are different after first oef.

1
2
line 1
eof


1
2
3
line 1
line 2
eof


The following code wants to compare two files, one line at a time.
But there is a syntax error in the do-while condition (on last line of code):
1
2
3
4
5
6
7
$ g++ compareFiles.cpp
compareFiles.cpp: In function ‘int main()’:
compareFiles.cpp:61:32: error: cannot convert ‘std::ifstream {aka std::basic_ifstream<char>}’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to ‘int feof(FILE*)’
     } while ( !feof(if_expected) && !feof(if_result) ); //until one file reaches end
                                ^
compareFiles.cpp:61:52: error: cannot convert ‘std::ifstream {aka std::basic_ifstream<char>}’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to ‘int feof(FILE*)’
     } while ( !feof(if_expected) && !feof(if_result) ); //until one file reaches end 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <string>
#include <fstream>
#include <string>
#include <iostream>

//open input file stream
void openInFile(std::ifstream& stream, const std::string& path)
{
    stream.open(path);

    if (!stream.is_open())
    {
        throw std::runtime_error("error: Unable to open input file " + path);
    }
}

int main()
{
    //result variables
    std::ifstream if_result;
    openInFile(if_result, "result.txt");
    std::string line_result;
    
    //expected variables
    std::ifstream if_expected;
    openInFile(if_expected, "expected.txt");
    std::string line_expected;

    unsigned int lineNumber = 0;

    do {
        std::getline(if_expected, line_expected);
        std::getline(if_result, line_result);
        lineNumber++;

        if (line_result != line_expected) //compare lines
        {
            std::cout << "line number " << lineNumber << " is different.\n";
            break;
        }

    } while ( !feof(if_expected) && !feof(if_result) ); //until one file reaches end
}

How to fix the syntax error?

Thank you.
Last edited on
How to fix the syntax error?

Don't use feof(). The feof() function only works with C FILE* not C++ streams.

By the way using eof to control a loop is not really recommend, use the actual reads instead.

1
2
3
4
    while(std::getline(if_expected, line_expected) && std::getline(if_result, line_result)
    {
         ...
    }

Thanks for the quick response jib.

But putting the getline() in the conditional causes the while loop to exit before "line 2" is compared to "eof":
1
2
line 1
eof


1
2
3
line 1
line 2
eof


mandarinka seems to get eof() working on a similar problem on http://www.cplusplus.com/forum/beginner/34805/#msg189369
But putting the getline() in the conditional causes the while loop to exit before "line 2" is compared to "eof"

The end-of-file marker is not a line; it doesn't make sense to compare a line to it.
In other words, if you try to read past the end-of-file, the read fails. What do you expect as the result of a failed read?
Last edited on
From http://www.cplusplus.com/reference/string/string/getline/
istream& getline (istream& is, string& str);
getline() returns reference to input istream&.
If the appropriate flag has been set with is's member function ios::exceptions, an exception of type ios_base::failure is thrown.

If both lines are "fail" (because eof) then the files are equal.
If one getline returns a string (line) and the other "fail" (eof), then the files are not equal.
if (line_result != line_expected) //compare lines
mbozzi wrote:
What do you expect as the result of a failed read?

Sorry, I should have been more precise: after
std::getline(stream, line)
returns a stream with its eofbit high, what do you expect line to contain?

To answer the question: line will contain all the stuff extracted before the EOF was reached (perhaps a blank line, if the file ends with a trailing newline.) This can very well coincide with the contents of lines in the other file.

Further reads on a failed stream will fail. Subsequent calls to getline will leave the string in its previous state. Source:
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://eel.is/c++draft/istream.unformatted#18

If one getline returns a string (line) and the other "fail" (eof), then the files are not equal.

As you say -- if exactly one stream has failed thanks to eofbit being set, the files are different. Comparing the strings you pass in to the getline() calls after a stream failure isn't sufficient.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
bool are_identical( std::istream& a, std::istream& b )
{
    std::string one, two ;

    while( std::getline( a, one ) && std::getline( b, two ) )
        if( one != two ) return false ; // lines don't compare equal, return false

    // if a is not in a failed/eof state, then b must be in a failed/eof state
    if(a) return false ;

    else // if a is in a failed/eof state (nothing more could be read from a)
        return !std::getline( b, two ) ; // return true if nothing more can be read from b
}
Thanks for the explanation mbozzi.
Last edited on
Thanks again mbozzi.

This works as intended:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <string>
#include <fstream>
#include <string>
#include <iostream>

//open input file stream
void openInFile(std::ifstream& stream, const std::string& path)
{
    stream.open(path);

    if (!stream.is_open())
    {
        throw std::runtime_error("error: Unable to open input file " + path);
    }
}

int main()
{
    //result variables
    std::ifstream if_result;
    openInFile(if_result, "result.txt");
    std::string line_result;

    //expected variables
    std::ifstream if_expected;
    openInFile(if_expected, "expected.txt");
    std::string line_expected;

    unsigned int lineNumber = 0;
    bool eofbit_1;
    bool eofbit_2;

    do {
        std::getline(if_expected, line_expected);
        eofbit_1 = if_expected.eof();

        std::getline(if_result, line_result);
        eofbit_2 = if_expected.eof();

        lineNumber++;

        if ( (line_result != line_expected) || (eofbit_1  != eofbit_2) ) //compare lines
        {
            std::cout << "line number " << lineNumber << " is different.\n";
            break;
        }

    } while ( !eofbit_1  && !eofbit_2 ); //until one file reaches end
}


input files:
line 1
1
2
line 1
line 2


output:
line number 2 is different.
Last edited on
Topic archived. No new replies allowed.