std::ios_base::ate and std::ios_base::trunc - c++

What the point of the std::ios_base::ate (other than std::ios_base::app, for example) and std::ios_base::trunc (other than std::ios_base::out, for example)?
And should i preferly write std::ios_base::smth instead of std::ios::smth?

std::ios_base::ate position the cursor at the end of the text whereas std::ios_base_app appends text (with a write operation) at the end, though you can still read from the beginning :)
std::ios_base::trunc truncates the file so it is emptied, whereas std::ios_base::out just specify you want to write to the stream.
I currently can't quote the standard (on my tablet and Acrobat Reader won't let met copy) but from paragraph 27.4.2.1.4 from ISO 14882:1998 the information you can see on the link is almost exact: http://cplusplus.com/reference/iostream/ios_base/openmode/
To sum up:
std::ios_base::app = append
Append at the end of the stream by "seek[ing] to end before each write"
std::ios_base::ate = At The End
Open and seek immediately at the end after opening
std::ios_base::binary = binary
Perform operation in binary as opposed to text
std::ios_base::in = input
Open in read mode
std::ios_base::out = output
Open in write mode
std::ios_base::trunc = truncate
Truncate the stream on opening.
These values are just flags, so you can open a stream in read/write binary at the end with :
std::ios_base::in | std::ios_base::out | std::ios_base::ate | std::ios_base::binary
Concerning the way of using those values, it is as you wish. They are declared as public static fields in std::ios_base class (see 27.4.2) thus it is possible to access them using std::ios::ate or even something like cout.binary !
The points where you must take attention is that std::ios_base::ate does NOT imply std::ios_base::app nor does std::ios_base::out implies std::ios_base::trunc. Each field has a different meaning, and a different case of use, though most of them can't be used alone :)

Related

File cleared out after reopening it with std::fstream

I want to open a file for reading, close it, and then open it again for writing using the same std::fstream. But when I reopen the file with writing permissions all the data inside is being cleared and it becomes 0 bytes long.
Here's my code:
char* data = new char[5];
std::fstream fs("myFile", std::ios::binary | std::ios::in);//opening with read
fs.read(data, 5);
fs.clear();
fs.close();
//Do some stuff
fs.open("myFile", std::ios::binary | std::ios::out);//opening with write
//The file is already empty at this point
When opening a file with the default write flag, i.e., std::ios::out with the <iostream> facility or "w" with the <cstdio> functions, there is a combination of POSIX flags happening behind your back - a truncate flag is added. This means that upon opening in write mode, the file content is discarded. To circumvent this, open the file the second time with
fs.open("myFile", std::ios::binary | std::ios::app);
The append mode moves the file cursor to the end of the file at each write operation and is not combined with the truncate flag, see here. Note that when you want to write to arbitrary positions in the existing file, you need to open it with
fs.open("myFile", std::ios::binary | std::ios::in | std::ios::out);
which does not truncate its content and allows for cursor positioning with the seek* functions.

fstream counterpart to O_RDWR | O_CREAT | O_APPEND [duplicate]

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:
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`
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.
Taking std::ios::binary as read, the remaining openmode probably you require is:
std::ios::in | std::ios::app
It's effect is as if to open the file with:
std::fopen(filename,"a+")
and the effect of that is:
open or, if it does not exist, create the file for reading and writing
write data at the end of the file.
If you open a file as an std::fstream with this openmode, it is not truncated if it exists. You may
read from the file wherever the fstream's tellg()\tellp() pointer points,
provided there is something there to read, and you can position that pointer
with the stream's seekg()\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.

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.
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`
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.
Taking std::ios::binary as read, the remaining openmode probably you require is:
std::ios::in | std::ios::app
It's effect is as if to open the file with:
std::fopen(filename,"a+")
and the effect of that is:
open or, if it does not exist, create the file for reading and writing
write data at the end of the file.
If you open a file as an std::fstream with this openmode, it is not truncated if it exists. You may
read from the file wherever the fstream's tellg()\tellp() pointer points,
provided there is something there to read, and you can position that pointer
with the stream's seekg()\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.

Does opening an fstream in fstream::out mode erase its current content ?

As the title says , does opening an fstream in fstream::out mode erase its current content ?
If no , what is the the best way to erase a .txt file using the fstream library .
And what is the equivalent of EOF in the C++ fstream library ?
When a std::basic_filebuf opens a file it acts as though it calls the relative C functions (whether it actually does so or not is up to the implementation).
The table in [filebuf.members] outlines what happens when certain flags are passed, if you only pass std::ios_base::out then it acts as though the file were opened with the stdio string "w", which will erase your file if it already exists.
The default for fstream if no flags are passed is to call basic_filebuf::open with std::ios_base::in | std::ios_base::out, which acts as though "r+" were used, which in turn positions the file position at the start of the file, but leaves the contents intact if it already exists.
For reference:

how to reset stream open flags?

So what I'm doing is creating a stringstream in binary mode. Somewhere along the line I don't want to treat it as binary anymore but as a regular string stream.
Looking through the documentation the only time streams care about whether they are binary, input or output (ios_base::openmode flags) is at construction. You can change the manipulator flags and the error flags, but apparently not the openmode flags? Maybe I'm not looking hard enough?
So what I'm currently doing is something like
std::stringstream memory( ios_base::in | ios_base::out | ios_base::binary );
boost::iostreams::copy( *source_file, memory );
And somewhere along the line I would like to be able to do something like
memory.reset_openmode( ios_base::in | ios_base::out );
What you could do (and also what I would do) is that I would close the stream, then reopen the stream as a basic text file, setting the seekg(), and the seekp() flags as necessary.