Why can an `ifstream` be opened both for reading and writing? - c++

I've seen an interesting piece of code today:
ifstream fil;
fil.open( "ini.txt", std::ios::in | std::ios::out );
I was just about to rant about its brokenness, but to my astonishement I saw that cppreference.com apparently thinks this is correct:
http://en.cppreference.com/w/cpp/io/basic_ifstream/open
mode - specifies stream open mode. It is bitmask type, the following constants are defined:
in: open for reading
out: open for writing
How can an ifstream, which, as far as I understand is an INPUT file stream, be opened both for reading and writing?
Shouldn't it necessarily be fstream instead of ifstream?

std::ifstream is like a handle over a std::basic_filebuf. You can even access that buffer from the handle with a call to std::basic_ifstream::rdbuf.
You can steal that buffer from the handle, and assign it to another (I won't go into how it's done). And here's the interesting thing. You can move that very buffer from an ifstream to an ofstream. And that requires being able to open the buffer for writing. As such, the very same reference page you linked says this:
Effectively calls rdbuf()->open(filename, mode | ios_base::in)
This is a convenience function to avoid manipulating the buffer itself later.

you need to use fstream:
fstream file("input.txt", ios::in | ios::out | ios::app);
int data;
file >> data;
file << data +1;
file.close();

Related

c++ - fstream and ofstream

What is the difference between:
fstream texfile;
textfile.open("Test.txt");
and
ofstream textfile;
textfile.open("Test.txt");
Are their function the same?
ofstream only has methods for outputting, so for instance if you tried textfile >> whatever it would not compile. fstream can be used for input and output, although what will work depends on the flags you pass to the constructor / open.
std::string s;
std::ofstream ostream("file");
std::fstream stream("file", stream.out);
ostream >> s; // compiler error
stream >> s; // no compiler error, but operation will fail.
The comments have some more great points.
Take a look at their pages on cplusplus.com here and here.
ofstream inherits from ostream. fstream inherits from iostream, which inherits from both istream and stream. Generally ofstream only supports output operations (i.e. textfile << "hello"), while fstream supports both output and input operations but depending on the flags given when opening the file. In your example, the open mode is ios_base::in | ios_base::out by default. The default open mode of ofstream is ios_base::out. Moreover, ios_base::out is always set for ofstream objects (even if explicitly not set in argument mode).
Use ofstream when textfile is for output only, ifstream for input only, fstream for both input and output. This makes your intention more obvious.

fstream input and output position are the same although inherited from istream and ostream

I want to to delete all data in binary files in the range: 10-19.
fstream myFile(f.bin, ios_base::in | ios_base::out | ios_base::app | ios_base::binary);
myFile.seekg(20);
myFile.seekp(10);
myFile << myFile;
myFile.close();
The problem is that internal position is stored in a single place.
Although here: http://www.cplusplus.com/reference/istream/iostream/
it is stated that it inherited from different base classes, and should been stored twice.
I understand I can use 2 different streams. But I am asking how to achieve this with a single stream?
What about using intermediate stream which is not a file stream- to avoid reopening the file again?

Is ios::in needed for ifstream's opened in binary mode?

What's the difference between these two? Isn't the in flag object thing redundant? Thanks.
std::ifstream file1("one.bin", std::ifstream::in | std::ifstream::binary);
std::ifstream file2("two.bin", std::ifstream::binary);
From the docs on ifstream class constructor:
binary (binary) Consider stream as binary rather than text.
in (input) Allow input operations on the stream.
So when reading from a file, I would use std::ifstream::in flag not because it's required (or not) but because it would be a good programming practice to let a programming interface know what you are going to use it for.
Edit:
The following is taken from http://www.cplusplus.com/doc/tutorial/files/, about open() member function though (but the constructors in the code in the question probably call open() copying the mode flags without modification).
class: default mode parameter
ofstream: ios::out
ifstream: ios::in
fstream: ios::in | ios::out
For ifstream and ofstream classes, ios::in and ios::out are
automatically and respectively assumed, even if a mode that does not
include them is passed as second argument to the open() member
function.
Nevertheless, many examples over the Web use ifstream::in when showing a construction of an ifstream object. Could really be some kind of a superstition practice, instead of a programming one.
binary, in this case, only refers to the method of reading or writing. In regular mode on windows, '\n' is translated to '\r''\n'. This can affect both reading and writing, so binary mode turns this off. out|binary makes just as much sense as in|binary
I can't find authoritative documentation online.
Edit I can't even find a proper reference in my copy the Josuttis Book, 8th printing. It should have been in section 13.9 pp. 627-631
Empirical evidence suggests it is redundant IFF none of std::ios::in or std::ios:out are passed:
#include <fstream>
#include <iostream>
int main(int argc, char** args)
{
std::ifstream ifs(args[0], std::ios::binary);
std::cout << ifs.rdbuf() << std::flush;
return 0;
}
Succeeds:
test | md5sum
md5sum test
show the same hash sum.
// ...
std::ifstream ifs(args[0], std::ios::out | std::ios::binary);
will fail (zero bytes output)
test | wc -c # shows 0
From cplusplus.com reference page, there is no difference.
in is always set for ifstream objects (even if explicitly not set in argument mode).
It's the same for ofstream. Therefore, you don't need to set std::ios::in for ifstream or std::ios::out for ofstream, even if you have set std::ios::binary which omits the in/out mode.

fstream >> int failing?

Any idea why the following would fail?
std::fstream i(L"C:/testlog.txt", std::ios::binary | std::ios::in);
int test = 0;
i >> test;
fail() is returning true. The file exists and is opened.
I checked
i._Filebuffer._Myfile._ptr
and it is pointer to a buffer of the file so I don't see why it is failing.
You're opening the file in binary mode. The extraction operators were meant to be used with text files. Simply leave out the std::ios::binary flag to open the file in text mode.
If you actually do have a binary file, use the read() function instead.
Edit: I tested it too, and indeed it seems to work. I got this from CPlusPlus.com, where it says:
In binary files, to input and output data with the extraction and insertion operators (<< and >>) and functions like getline is not efficient, since we do not need to format any data, and data may not use the separation codes used by text files to separate elements (like space, newline, etc...).
Together with the description of ios::binary, which simply states "Consider stream as binary rather than text.", I'm utterly confused now. This answer is turning into a question of its own...
The following:
#include <fstream>
#include <iostream>
using namespace std
int main() {
std::fstream i("int.dat" , std::ios::binary | std::ios::in);
int test = 0;
if ( i >> test ) {
cout << "ok" << endl;
}
}
prints "ok" when given a file containing the characters "123". Please post a similar short test that illustrates your code failing.

How to use different ifstream modes in c++?

According to the reference, if I use ifstream infile ( "test.txt" , ifstream::in ); it will Allow input operations on the stream. But what are some of the examples of the "input operations"?
Is ifstream infile ( "test.txt" , ifstream::in | ifstream::binary ); the right syntax to use multiple flags?
Will it make a difference if I change ifstream:: to iso:: ?
Thank you
According to the reference, if I use ifstream infile ( "test.txt" ,
ifstream::in ); it will Allow input
operations on the stream. But what are
some of the examples of the "input
operations"?
Reading from a file which would mean everything an input stream can support. See istream member functions. Typically, you can do both formatted (using >>) and unformatted reads (using read). Remember that ifstream is a specialization of the basic_ifstream template for char type. Depending on your needs, say to read UTF-16 encoded file, you may have to use a different specialization (wifstream) or even use a special locale (read this to know more about locales).
Is ifstream infile ( "test.txt" , ifstream::in | ifstream::binary );
the right syntax to use multiple
flags?
Yes.
Will it make a difference if I change ifstream:: to iso:: ?
No.
Stream operations are extraction << and insertion >>. When you do the following assuming
file is of fstream type:
file << 5 << 6.5 << "Hello World!"; // insertion of data (output)
file >> x >> y >> str; // exaction of data (input)
You could also, deal with the stream as a binary stream. In that case, it doesn't really look like a "stream" of data but that gives you random access to the data. In some cases you can't use the binary mode, especially if your data is not available like a network stream. Insertion and Extraction, are the two main operations on streams.
ifstream is created as an input stream by default. So, std::ios::in is redundant in this case. You are using the flags correctly.
all streams inherit from ios. So, the flags are available in both places, you can either retrieve them from ios directly or from fstream.