Std :: ofstream with std :: ate does not open at the end

I am trying to open a file for output and add to it. After adding to it, I want to transfer my output position to another location in the file and overwrite the existing data. As far as I understand, std::ios_base::app will be force , all entries will be at the end of the file, which I do not want to do. As such, I believe that std::ios_base::ate is the correct flag to go to std::ofstream::open() . However, it does not seem to work as expected:

 // g++ test.cpp // clang++ test.cpp // with and without -std=c++11 #include <iostream> #include <fstream> int main() { std::streampos fin, at; { std::ofstream initial; initial.open("test", std::ios_base::out | std::ios_base::binary); if ( not initial.good() ) { std::cerr << "initial bad open" << std::endl; return 1; } int b = 100; initial.write((char*)&b, sizeof(b)); initial.flush(); if ( not initial.good() ) { std::cerr << "initial write bad" << std::endl; return 1; } fin = initial.tellp(); } { std::ofstream check; check.open("test", std::ios_base::out | std::ios_base::binary | std::ios_base::ate); if ( not check.good() ) { std::cerr << "check bad open" << std::endl; return 1; } at = check.tellp(); if ( fin != at ) { std::cerr << "opened at wrong position!\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl; return 1; } int bb = 200; check.write((char*)&bb, sizeof(bb)); check.flush(); if ( not check.good() ) { std::cerr << "check write bad" << std::endl; return 1; } at = check.tellp(); } if ( (fin + std::streampos(sizeof(int))) != at ) { std::cerr << "overwrite?\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl; return 1; } return 0; } 

In particular, it seems that std::ios_base::ate does not move the initial output pointer to the end with the example described above. Obviously, this will cause the first record to be overwritten at the beginning of the file (which caused my problem).

It seems that the implementation is incorrect, or cplusplus.com is incorrect ("The output position starts at the end of the file.") And cppreference.com is ambiguous ("look for the end of the stream immediately after opening": which stream?).

There is obviously an easy way: just use stream.seekp(0, std::ios_base::end) .

So my question is: is my code wrong? Improper execution? Are link sites listed? Any insight would be appreciated.

+7
c ++ c ++ 11 fstream
source share
1 answer

As can be seen from the following diagram in N4296 [filebuf.members]

file io

Binary combination binary | out binary | out will open a file equivalent to stdio "wb" , which will be truncate to zero length or create binary file for writing (N1570 7.21.5.2).

As inaccurate as this sounds to ofstream , you need to add the in flag if you don't want your file to be truncated, or app if you want to avoid truncating and look for the end of the file for each record.

Bonus tip: unlike fstream , ifstream and ofstream will automatically either std::ios_base::in and std::ios_base::out respectively with any flags that you provided to the constructor, or open . You can also use the object itself to access the flags:

 std::ofstream check("test", check.in | check.binary | check.ate); 

Checks for good can also be reduced to if (!initial) , etc.

+7
source share

All Articles