What is the proper set of I/O flags for a std::fstream
, where I want to be able to read from and write to the file, without truncating the file if it exists, but creating it if it does not?
I've tried
std::ios::binary | std::ios::in | std::ios::out
std::ios::binary | std::ios::in | std::ios::out | std::ios::ate
but neither of these create the file if it does not already exist.
I don't want std::ios::app
, because I also need to be able to seek around the file at will, with both the get and put cursors.
One workaround, I suppose, would be to instantiate an std::ofstream
first, then immediately close it and open the stream I really want, but that seems messy if it can be avoided with a single stream object.
At this time, I'm concluding that
std::ios::in
outright prevents this, and that I must use the workaround.So:
An investigation, from a Linux perspective (though much of this likely applies to other Unices):
At the syscall layer, you want
open(O_RDWR | O_CREAT, 0666)
(but notO_TRUNC
orO_APPEND
or a bunch of other flags, though arguably all files should be opened withO_CLOEXEC | O_LARGEFILE
, but that's beside the point)At the libc layer, there is no standard
mode
string that impliesO_CREAT
withoutO_TRUNC
. However, you could useopen
followed byfdopen
.At the C++ library level, there is no standard way to pass the desired flags. However, using implementation-specific classes/functions or third-party libraries, it is possible; see How to construct a c++ fstream from a POSIX file descriptor?
Personally, I tend to do all I/O at the C or even syscall level, since the API is a lot nicer and it's more predictable. For input/output of class instances, I have my own templates.
Taking
std::ios::binary
as read, the remainingopenmode
probably you require is:It's effect is as if to open the file with:
and the effect of that is:
If you open a file as an
std::fstream
with thisopenmode
, it is not truncated if it exists. You may read from the file wherever thefstream
'stellg()\tellp()
pointer points, provided there is something there to read, and you can position that pointer with the stream'sseekg()\seekp()
for reading. However, all writes will be appended to the end of the file.This openmode will therefore fit your bill unless you need to perform writes into existing data.