You can open a file for both input and output by declaring an fstream object. When declaring an fstream object, you must use enough of the open mode flags mentioned earlier to let the file system know whether you want to input, output, or both. To switch from output to input, you need to either flush the stream or change the file position. To change from input to output, change the file position. To create a file via an fstream object, you need to use the ios::trunc open mode flag in the constructor call if you will actually do both input and output.
Iostream buffering
Good design practice dictates that whenever you create a new class, you should endeavor to hide the details of the underlying implementation as much possible from the user of the class. You show them only what they need to know and make the rest private to avoid confusion. When using inserters and extractors, you normally don’t know or care where the bytes are being produced or consumed, whether you’re dealing with standard I/O, files, memory, or some newly created class or device.
A time comes, however, when it is important to communicate with the part of the iostream that produces and consumes bytes. To provide this part with a common interface and still hide its underlying implementation, the standard library abstracts it into its own class, called streambuf. Each iostream object contains a pointer to some kind of streambuf. (The kind depends on whether it deals with standard I/O, files, memory, and so on.) You can access the streambuf directly; for example, you can move raw bytes into and out of the streambuf, without formatting them through the enclosing iostream. This is accomplished by calling member functions for the streambuf object.
Currently, the most important thing for you to know is that every iostream object contains a pointer to a streambuf object, and the streambuf object has some member functions you can call if necessary. For file and string streams, there are specialized types of stream buffers, as the following figure illustrates.
To allow you to access the streambuf, every iostream object has a member function called rdbuf( ) that returns the pointer to the object’s streambuf. This way you can call any member function for the underlying streambuf. However, one of the most interesting things you can do with the streambuf pointer is to connect it to another iostream object using the << operator. This drains all the characters from your object into the one on the left side of the <<. If you want to move all the characters from one iostream to another, you don’t have to go through the tedium (and potential coding errors) of reading them one character or one line at a time. It’s a much more elegant approach.
For example, here’s a simple program that opens a file and sends the contents to standard output (similar to the previous example):.
//: C04:Stype.cpp
// Type a file to standard output
#include
#include
#include "../require.h"
using namespace std;
int main() {
ifstream in("Stype.cpp");
assure(in, "Stype.cpp");
cout << in.rdbuf(); // Outputs entire file
} ///:~
An ifstream is created using the source code file for this program as an argument. The assure( ) function reports a failure if the file cannot be opened. All the work really happens in the statement:.
cout << in.rdbuf();
which sends the entire contents of the file to cout. This is not only more succinct to code, it is often more efficient than moving the bytes one at a time.
A form of get( ) allows you to write directly into the streambuf of another object. The first argument is a reference to the destination streambuf, and the second is the terminating character (‘\n’ by default), which stops the get( ) function. So there is yet another way to print a file to standard output:.
//: C04:Sbufget.cpp
// Copies a file to standard output
#include
#include
#include "../require.h"
using namespace std;
int main() {
ifstream in("Sbufget.cpp");
assure(in);
streambuf& sb = *cout.rdbuf();
while (!in.get(sb).eof()) {
if (in.fail()) // Found blank line
in.clear();
cout << char(in.get()); // Process '\n'
}
} ///:~