Concepts / Ordinary Output and Input Streams in C++

Ordinary Output and Input Streams in C++

A file stream can be used as an ordinary stream: ofs acts as an ordinary ostream, just like cout, and ifs acts as an ordinary istream, just like cin.

  • Programming

Writing to a File With the Habits You Already Have

Most C++ programs that print something already rely on a stream. The object cout accepts output, and the object cin supplies input. A natural question follows: if a program wants to write to a file or read from one, does it need a completely different set of habits? The source answers this directly. A file stream can be used the same way as the ordinary stream objects you already know.

What do you think happens?

Given the statement ofs << "Total: " << total; where does the value of total end up?

  • On the screen, because << always writes to cout

  • In the file that ofs refers to

  • Nowhere, because ofs cannot receive data

Reveal answer
Answer:

In the file that ofs refers to

The source says ofs can be used as an ordinary ostream, just like cout. The statement has the same form as one sending values to cout; only the destination changes, from the screen to the file.

This article follows one question through: what role does a file stream play in a program, and how closely does it match cout and cin?

Shared Stream Classes Behind cout and ofs

The reason the two objects behave alike is that they belong to related stream classes. The output file stream ofstream and the console object cout both work as output streams. Similarly, the input file stream ifstream and the console object cin both work as input streams. The diagram below shows these relationships: the general ostream and istream classes sit at the top, and the specific objects you use sit beneath them.

ostreamoutput stream classofstreamfile output classofsfile output objectistreaminput stream classcoutconsole outputifsfile input objectifstreamfile input classcinconsole inputofstream is a kind of ostreamcout is an ostream objectifstream is a kind of istreamcin is an istream objectofs is an ofstream objectifs is an ifstream object
How can one function accept either cout or a file stream, and what class relationship makes that possible? Both ofs and cout are output streams, and both ifs and cin are input streams.

The source itself states only the behavioral claim: ofs acts as an ordinary ostream, and ifs acts as an ordinary istream. The class relationships above are the standard-library structure that makes that claim work in practice, which is why the same kinds of operations apply to both.

Output Through ofs Like cout

The source says that ofs can be used as an ordinary ostream, just like cout. In practical terms, a program can treat ofs as a destination for output in the same manner it treats cout. Code that sends values into cout can be understood as sending values into ofs, with the file as the final destination. The behavior of the statements does not need to be relearned; what changes is where the data lands.

cpp
Output
Console: Total: 42
File report.txt contains: Total: 42
Notes on the code
  • The cout line sends the text and value to the screen.
  • The ofs line uses the same << operators and the same kind of statement.
  • Only the destination differs: the file named report.txt instead of the screen.

The two statements in the example are identical in shape. A learner who already writes cout << value can write ofs << value without learning a new set of operators.

Tracing One Output Function Through Two Destinations

Because ofs is an ordinary ostream, a function can accept a generic output stream and write to whichever stream the caller supplies. The following generated example shows one function used with both cout and ofs. Notice that the function body never mentions the screen or the file.

cpp
Output
Score: 90   (printed to the screen)
scores.txt now contains: Score: 90
Notes on the code
  • The parameter out is a reference to a general ostream.
  • The first call passes cout, so the text goes to the screen.
  • The second call passes ofs, so the same text goes to the file.
writeReport(cout,90)out refers to coutScreenwriteReport(ofs,90)out refers to ofsscores.txtpasses couttext printedpasses ofstext written
When the same write call runs, which object receives the data, and how does the data travel from the caller to the file or the console? The write goes to whichever stream object the caller passed in.

Input Through ifs Like cin

The same reasoning applies in the opposite direction. The source says that ifs can be used as an ordinary istream, just like cin. A program that reads values from cin can therefore read values from ifs, with the file supplying the data instead of the keyboard. The input side mirrors the output side: ofs plays the role of an output stream, and ifs plays the role of an input stream.

cpp
Output
(typed 7 at the keyboard)
Keyboard gave: 7
File gave: 15   (if numbers.txt begins with 15)
Notes on the code
  • The cin line reads from the keyboard.
  • The ifs line uses the same >> operator on a different source.
  • The file supplies the data, so the value read depends on the file's contents.

Taken together, the two directions form one picture. Output goes from the program into a file through ofs. Input comes from a file into the program through ifs. In both cases the program interacts with a stream object in a way it already understands from cout and cin.

The Condition Behind the Comparison

The statement that ofs and ifs behave like cout and cin begins with a condition: assuming that the tests succeeded. The source does not spell out those tests in this passage, but the condition itself matters. The comparison with ordinary streams holds only when the file stream is in a working state. A learner should not assume that every file stream will behave like cout or cin in every circumstance; the claim is conditional.

Open file into ofsor ifsDid the testssucceed?Use like cout or cincomparison holdsComparison does notholdnot assumedafter openingyesno
What must be true about the stream after opening the file for it to behave like cout or cin, and what happens if that check fails? The source attaches the comparison to a successful check and does not detail the failure case.

String Streams in the sstream Header

File streams connect a program to a file. A different kind of stream connects a program to a string. The source states that the sstream header of the standard library provides streams to and from a string. This means the stream idea that applies to files and to the screen also has a counterpart that works with string data held in memory.

The source gives this topic only a brief mention and does not show the operations of string streams. What it does establish is the existence of streams to and from a string and the header that provides them, so a learner knows where to look next.

Mistakes Learners Make With Ordinary Streams

  • Common mistake

    Assuming every file stream behaves like cout or cin in every situation

    Why it fails

    The source attaches the comparison to the tests having succeeded, so the claim is conditional.

    Do this instead

    Check the stream state after opening before relying on it as an ordinary stream.

  • Common mistake

    Relearning the statement form when switching from cout to ofs

    What it looks like
    ofs << "Total: " << total;
    Why it fails

    The source says the way the program sends data stays familiar; only the destination changes.

    Do this instead

    Keep the same << operators and change only the stream object's destination.

  • Common mistake

    Thinking a file read with ifs works the same way as cin regardless of the file contents

    Why it fails

    The value read with ifs comes from the file, so the result depends on what the file holds.

    Do this instead

    Think of ifs as cin with the file supplying the data instead of the keyboard.

  • Common mistake

    Treating the sstream header as if the source had already taught its string stream operations

Checking Your Understanding of Stream Roles

EASY

A function is written as void log(std::ostream& out) { out << "Done" << std::endl; }. Explain in your own words which two objects could be passed to log, and where the text "Done" would go in each case.

Hints
  • Both cout and an ofstream object can be treated as an ostream.
  • The destination depends on which object the caller passes in, not on the body of log.
MEDIUM

Write a short program that opens an output file named notes.txt with an ofstream named ofs, then writes the line Hello to it using the same << form you would use with cout. Before writing, state what you would check to decide whether the comparison with cout still holds.

Hints
  • Use the same statement shape as cout << "Hello".
  • The source attaches the comparison to a working stream state, so mention that check.

Key Takeaways

  • A file stream such as ofs can be used as an ordinary ostream, just like cout, so output statements keep the same form and only the destination changes to the file.
  • A file stream such as ifs can be used as an ordinary istream, just like cin, so the program reads values the same way while the file supplies the data.
  • The source makes this comparison conditional on the tests having succeeded, so the stream must be in a working state before it is treated as ordinary.
  • The sstream header of the standard library provides streams to and from a string, extending the stream idea to in-memory string data; the source introduces this only briefly.

Related concepts

More concepts starting with O