Search code examples
c++fstreamput

cannot output the last row with fstream


void reverse_output(string s, fstream& file, streamoff initial_pos)
{
    const char* a = s.c_str();
    file.seekp(initial_pos, ios::beg);
    for (int i = s.length() - 1; i >= 0; i--)
    {
        file.put(a[i]);
    }
}
int main()
{
    string file_name = "E:\\WorkSpace\\ConsoleApplication2\\Debug\\2.txt";
    fstream file;
    file.open(file_name.c_str());

    string row;
    streamoff pos = 0;


    while (getline(file, row))
    {       
        reverse_output(row, file, pos);
        file.put('\n');
        pos = file.tellp();
        file.seekg(pos, ios::beg);
    }

    file.close();
    return 0;
}

I want to write a program which reverse each row of a file.
Say a file which contains:

123456
qwe

will be converted to the same file contains:

654321
ewq

I have written the above codes but they won't work for the last row. I suspect

while (getline(file, row))

is the main reason. Who could help me and tell me the real reason?


Solution

  • Your use of while (std::getline(file, row)) is OK. Your issue is that the last line of your file doesn't contain a newline! When reading the last line, its end is determined by touching the end of the file. When the stream touches the end of the file, the flag std::ios_base::eofbit gets set, i.e., file.eof() yields true.

    The next operation you do is trying to seek the stream using file.seekp(...). The call to seekp() creates a std::ostream::sentry on the file which will convert to false when file.good() is false. Having std::ios_base::eofbit set causes file.good() to be false. When the sentry object converts to false the seek operation fails and std::ios_base::failbit gets set.

    The easiest fix to the problem is to reset std::ios_base::eofbit at the start of the while-loop:

    while (getline(file, row))
    {       
        file.clear();
        // ...
    }
    

    Since the stream returned from std::getline() converted to true, only std::ios_base::eofbit can be set anyway: if either std::ios_base::failbit or std::ios_base::badbit had been set, the stream would convert to false.