ios::in Required for fstream to Not Wipe File

Jan 6, 2012 at 6:53am
I ran into a horrible bug today while I was writing an experimental serialization system. When I use fstream to open a file for writing (ios::out) but not for reading (ios::in), the contents of the file are completely wiped, leaving an empty file with the put pointer at 0, as if ios::trunc were enabled.

However, as soon as I turn on ios::in, everything works. The entire file is kept intact, and I can choose to write to only certain parts of the file without having to load a potentially huge file into memory.

Does anyone have an explanation for this? I don't have much experience with file IO, so I could have missed something obvious.

The problem occurs in this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ofstream file("output.txt", ios::out | ios::binary);

    file.seekp(0, ios::beg);
    file.write("abcdefghijklmnopqrstuvwxyz", 26);

    file.seekp(3, ios::beg);
    file.write("123", 3);

    file.close();

    file.open("output.txt", ios::out | ios::binary);

    return 0;
}


Reopening the file at the end causes the file to be empty after the program finishes. If I comment out that line, or add ios::in to its options, the file is untouched. I also have to add ios::in to the first opening if I want the contents of the file from the last execution to be used in the program.

I realize that I could just enable reading from all the files I write to, but I really want to know why this is happening in case I'm making a horrible mistake somewhere.
Jan 6, 2012 at 10:28am
> I really want to know why this is happening

For output file streams, the open mode iosbase::out is equivalent to iosbase::out|iosbase::trunc - the iosbase::trunc flag is implied even if it is omitted.

For bidirectional file streams, however, iosbase::trunc is not implied; it must be explicitly specified (if required).

See 30.3.2 Combining Open Modes in http://stdcxx.apache.org/doc/stdlibug/30-3.html


> I realize that I could just enable reading from all the files I write to

If you want to just write to (and not read from) a file, use a std::ofstream.
If you want to just read from (and not write to) a file, use a std::ifstream.
If you want to both read from and write to a file, use a std::fstream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create an empty file for writing: 
// If a file with the same name already exists its content is erased 
// and the file is treated as a new empty file.
std::ofstream file_a( "path_to_file_a" ) ;  

// Append to an existing file (or create a new file) for writing: 
// If a file with the same name already exists append data at the end of the file. 
// if it does not exist, create a new empty file.
std::ofstream file_b( "path_to_file_b", std::iosbase::app ) ;  

// Open an existing file for writing.  
// A file with the same name must already exist
// if it does not exist, open fails.
std::ofstream file_c( "path_to_file_c", std::iosbase::in|std::iosbase::out ) ;  

Last edited on Jan 6, 2012 at 10:29am
Topic archived. No new replies allowed.