Search code examples
c++fstreamostream

Multiple ostream on a file produces different order of output


Why does multiple ostream on a file being written to produce a different order of output? For example:

#include <iostream>
#include <fstream>
using namespace std;

void writeTo(string filename){
    ostream o;
    o.open(filename, ios::app);
    o << "Second\n";
    o.close();
}

int main(){
    ostream o;
    o.open("foo.txt", ios::app);
    o << "First\n";
    writeTo("foo.txt");
    o.close();
    return 0;
}

The output file is

Second
First

Why is this the case? Shouldn't it be First then Second?

I know I can achieve this behavior by having one stream and passing it by reference as such, but I'm confused what causes this behavior of multiple streams on the same file:

#include <iostream>
#include <fstream>
using namespace std;

void writeTo(ostream& o){
    o << "Second\n";
}

int main(){
    ostream o;
    o.open("foo.txt", ios::app);
    o << "First\n";
    writeTo(o);
    o.close();
    return 0;
}

Solution

  • It has to do with the order you .close() your ostreams.

    First you are opening the file in append mode, and buffering 'First,' but this doesn't actually reach the file yet.

    ostream o;
    o.open("foo.txt", ios::app);
    o << "First\n";
    

    Then, you open the file again, and buffer 'Second,' closing the file, and actually putting the buffer into the file.

    ostream o;
    o.open(filename, ios::app);
    o << "Second\n";
    o.close();
    

    Finally, you do o.close(); in your main function, outputting the first ostream, which contained 'First', into the file. Since it was opened in ios::app (append mode), that text goes to the end of the file, creating what you saw:

    Second
    First
    

    More reading:

    File opening modes: http://www.dummies.com/programming/cpp/open-modes-in-c/

    How ostream::close() works: http://www.cplusplus.com/reference/fstream/ofstream/close/

    To avoid this in the future, typically you should close the file before you open it again, or flush the file after you wrote it the first time before you write it again, like seen here: http://www.cplusplus.com/reference/ostream/ostream/flush/

    ostream::flush() forces the buffer to be moved into the file.