I've always read and been told that when dealing with binary files that one should use read() and write() as opposed to the << and >> operators as they are meant for use with formatted data. I've also read that it is possible to use them, but it is an advanced topic, which I can't find where anyone dives into and discusses.
I recently saw some code which did the following:
std::ifstream file1("x", ios_base::in | ios_base::binary);
std::ofstream file2("y", ios_base::app | ios_base::binary);
file1 << file2.rdbuf();
When I pointed out the use of the << operator with the binary file, I was told that the rdbuf() call returns a streambuf * and that << overloads the streambuf* and does a direct copy with no formatting and is thus safe.
Is this true and also safe? How about efficiency? Any gotchas? Details would be much appreciated.
Thanks!
Yes (see 27.6.2.5.3/6 where the overload of << for streambuf is described).
It's entirely safe and a reasonable way to copy streams.
Note that it also allows stuff like:
std::ifstream file_in1("x1", ios_base::in | ios_base::binary);
std::ifstream file_in2("x2", ios_base::in | ios_base::binary);
std::ofstream file_out("y", ios_base::app | ios_base::binary);
file_out << file_in1.rdbuf() << "\nand\n" << file_in2.rdbuf();
In § 27.7.3.6.3 of the C++ standard, it's mentioned that
basic_ostream<charT,traits>& operator<<
(basic_streambuf<charT,traits>* sb);
Effects: Behaves as an unformatted output function (as described in 27.7.3.7, paragraph 1).
§ 27.7.3.7 describes "unformatted input" which is basically a binary copy. This means that "unformatted" ostream functions are safe for binary data. The other "unformatted" functions mentioned in the standard that I can find are put, write and (officially) flush.
Related
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();
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.
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?
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.
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.