Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I open a file for reading & writing, creating it if it does not exist, without truncating it?

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.

like image 383
Lightness Races in Orbit Avatar asked Jul 17 '15 19:07

Lightness Races in Orbit


People also ask

How do I open a file for reading and writing?

'r+' opens the file for both reading and writing. On Windows, 'b' appended to the mode opens the file in binary mode, so there are also modes like 'rb', 'wb', and 'r+b'. Also reading then writing works equally well using 'r+b' mode, but you have to use f.

How do I read a text file?

To read from a text fileUse the ReadAllText method of the My. Computer. FileSystem object to read the contents of a text file into a string, supplying the path. The following example reads the contents of test.


2 Answers

At this time, I'm concluding that std::ios::in outright prevents this, and that I must use the workaround.

So:

if (!std::ostream(path.c_str()))
   throw std::runtime_error("Could not create/open file");

std::fstream fs(path.c_str(), std::ios::binary | std::ios::in | std::ios::out);
if (!fs)
   throw std::runtime_error("Could not open file");

// ... use `fs`
like image 184
Lightness Races in Orbit Avatar answered Sep 30 '22 16:09

Lightness Races in Orbit


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 not O_TRUNC or O_APPEND or a bunch of other flags, though arguably all files should be opened with O_CLOEXEC | O_LARGEFILE, but that's beside the point)

At the libc layer, there is no standard mode string that implies O_CREAT without O_TRUNC. However, you could use open followed by fdopen.

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.

like image 38
o11c Avatar answered Sep 30 '22 14:09

o11c