How to truncate a file while it is open with fstream
I don't think you can get "atomic" operation but using the Filesystem Technical Specification that has now been accepted as part of the Standard Library (C++17) you can resize the file like this:
#include <fstream>
#include <sstream>
#include <iostream>
#include <experimental/filesystem> // compilers that support the TS
// #include <filesystem> // C++17 compilers
// for readability
namespace fs = std::experimental::filesystem;
int main(int, char*[])
{
fs::path filename = "test.txt";
std::fstream file(filename);
if(!file)
{
std::cerr << "Error opening file: " << filename << '\n';
return EXIT_FAILURE;
}
// display current contents
std::stringstream ss;
ss << file.rdbuf();
std::cout << ss.str() << '\n';
// truncate file
fs::resize_file(filename, 0);
file.seekp(0);
// write new stuff
file << "new data";
}
How to clear the content of a file after it is opened using fstream?
Hate to disappoint you, but..
There's no standard way of clearing the contents of a file from an open std::fstream, the straight forward way is therefore to handle the two operations as what they really are.. two operations.
First handle all the reading, and later the writing (through a different stream object).
The solution
In other words; first open the file in read-only mode (std::ifstream) and read the data you are interested in, then discard that file-handle and open the file again.. this time in write-only and truncation mode (std::ofstream), so that you will clear the contents of the file.
std::ifstream ifs ("some_file.txt");
... // read old data
ifs.close ();
std::ofstream ofs ("some_file.txt", std::ios::out | std::ios::trunc); // clear contents
... // write new data
ofs.close ();
Why is an fstream truncated when it is opened with the flags ios::ate and ios::out?
Despite the implication in the standard, ios::ate doesn't actually have anything to do with whether or not truncation happens.
Internally, the fstream object has a buffer (a filebuf object). Whether the contents of the buffer are appended to the file when you write, are purely dependent on the combination of ios::in and ios::out - you need both to append. (Or ios::app)
ios::ate doesn't append the buffer - it helps you calculate file size and relative positions within the file. Different things.
See this question for discussion of the various modes - you will note ios::ate has no effect on the mode, and that you need in|out (or app) to get +.
Why does fstream.open() fail If the mode has both trunc and app set?
The iostream
open modes correspond roughly to the fopen
mode in the C library and fopen
has a w
mode that truncates and an a
mode that appends, but no combination of the two.
Opening a file in append mode but truncating the file
It works because
std::ios_base::out | std::ios_base::app & std::ios_base::out | std::ios_base::trunc
==
std::ios_base::out | (std::ios_base::app & std::ios_base::out) | std::ios_base::trunc
==
std::ios_base::out | 0 | std::ios_base::trunc
==
std::ios_base::out | std::ios_base::trunc
which is actually what you want: open file for writing and truncate it if it exists.
(And of course std::ios_base::trunc
is redundant, as mentioned by 0x499602d2 - you could specify just std::ios_base::out
)
Does std::ofstream truncate or append by default?
The short version
It truncates by default.
The medium version
The standard is basically spaghetti on this, but it eventually boils down to saying that it's the equivalent of saying fopen(const char*, "w")
(27.9.1.4 [filebuf.members]), which then points us towards the ISO C 7.9 standard.
Checking that out provides us with §7.19.5.3, "The fopen function", which specifies the behavior when "w" is passed:
w truncate to zero length or create text file for writing
The long version
If you'd like to follow the spaghetti trail yourself, start with 27.9.1.11 [ofstream.cons], which describes the constructor's behavior asEffects: Constructs an object of
class basic_ofstream<charT,traits>
, initializing the base class with
basic_ostream(&sb
) and initializingsb
withbasic_filebuf<charT,traits>())
(27.7.3.2, 27.9.1.2),
then callsrdbuf()->open(s, mode|ios_base::out)
. If that function returns a null pointer, calls
setstate(failbit)
.
Where rdbuf()
returns basic_filebuf<charT,traits>*
(27.9.1.13 [ofstream])
Which leads us to 27.9.1.1 [filebuf], or more specifically, 27.9.1.4 [filebuf.members] , which describes the open
function:
basic_filebuf<charT,traits>* open(const char* s, ios_base::openmode mode);
as
Effects: If
is_open() != false
, returns a null pointer. Otherwise, initializes the filebuf as required.
It then opens a file, if possible, whose name is the NTBSs
(as if by callingstd::fopen(s,modstr)
).
The NTBSmodstr
is determined frommode & ~ios_base::ate
as indicated in Table 132. If mode is
not some combination of flags shown in the table then the open fails.
NTBS: Null-terminated byte-string
Table 132 describes equivalence rules between C++ ios_base::openmode
and C-style stdio strings:
Table 132 — File open modes
|
| 'ios_base' flag combination | 'stdio' equivalent |
| binary | in | out | trunc | app | |
| | | + | | | "w" |
| etc... |
Which leads us to a footnote on the same page that states:
...the function signatures
fopen(const char*, const char*)
andfseek(FILE*, long,
are declared, in
int)<cstdio>
(27.9.2).
Which sends us, predictably, to 27.9.2 [c.files], which provides the nearly useless Table 134, but then references the C standard:
See also: ISO C 7.9, Amendment 1 4.6.2.
Which I talk about in the main portion of this answer.
Related Topics
Class Type Non-Type Template Parameter Initialization Does Not Compile
Vector::At VS. Vector::Operator[]
What Does the Fpermissive Flag Do
Why Is Std::Fill(0) Slower Than Std::Fill(1)
Why Does Clang Optimize Away X * 1.0 But Not X + 0.0
How to Read/Write a Struct in Binary Files
What's a Good Hash Function for English Words
Does Constraint Subsumption Only Apply to Concepts
Getting a Vector<Derived*> into a Function That Expects a Vector<Base*>
Explanation of Function Pointers
Understanding the Example on Lvalue-To-Rvalue Conversion
Multiset, Map and Hash Map Complexity
Why Does Visual Studio 2013 Error on C4996
Difference Between Using Character Pointers and Character Arrays