C++ Standard Library · Lesson 12

I/O Streams

The one model that handles the console, files, and in-memory text: insert with <<, extract with >>. Plus the modern way to format output.

🎯 Read and write data — console, files, strings — one way
The one idea

C++ I/O is stream-based: a stream is a flow of characters you insert into with << or extract from with >>. The same two operators drive the console (cout/cin), files (fstream), and in-memory text (stringstream) — learn them once, use them everywhere.

01 Console: cout, cin, cerr

std::cout is the output stream, std::cin the input. The << ("put to") and >> ("get from") operators chain, and pick the right behavior for each type automatically.

#include <iostream>

std::cout << "x = " << 42 << ", ok? " << true << "\n";   // chains, type-aware

int age;
std::cout << "Age? ";
std::cin >> age;            // reads one whitespace-delimited token, parses to int

std::string line;
std::getline(std::cin, line);   // reads a WHOLE line (including spaces)

std::cerr << "error!\n";     // cerr = error stream (unbuffered, separate from cout)
Run on godbolt.org — add input under the "stdin" panel.
⚠ The classic >>-then-getline trap cin >> age leaves the newline in the buffer, so a following getline reads an empty line. Fix: consume the leftover with std::cin.ignore(), or read everything with getline + parse. Also: a failed >> (bad input) puts the stream in a fail state — check if (cin >> x).

Source: cppreference — std::cout / iostream.

02 One model, three destinations

The power of streams is uniformity: << behaves the same whether the other end is your terminal, a file, or a string in memory. They all derive from the same ostream/istream base.

your code: stream << data (works on any std::ostream) std::cout the console std::ofstream a file on disk ostringstream a string in memory
Write code against std::ostream& and it works for all three. The destination is just which stream object you hand it.

03 File streams — and RAII again

Open a file by constructing a stream; it closes itself when the stream object goes out of scope (RAII, Lesson 1). No manual close() needed.

#include <fstream>

// write
{
    std::ofstream out("log.txt");       // opens (creates/truncates)
    out << "hello\n" << 42 << "\n";     // same << as cout
}                                       // ← file flushed & closed here, automatically

// read line by line
std::ifstream in("log.txt");
if (!in) { /* open failed — handle it */ }
std::string line;
while (std::getline(in, line))         // loop ends at EOF or error
    process(line);
💡 A stream is "truthy" while it's good if (!in) tests for failure (open failed, bad read). while (getline(in, line)) works because getline returns the stream, which converts to false at end-of-file. This is the idiomatic read loop.

Source: cppreference — file streams.

04 stringstream — parse and build in memory

A stringstream is a stream backed by a std::string. It's the standard tool for splitting a line into fields (extract with >>) and for building a string piece by piece.

#include <sstream>

// PARSE: pull typed tokens out of a line
std::istringstream iss("3 14 159");
int a, b, c;
iss >> a >> b >> c;          // a=3, b=14, c=159  (whitespace-split + parsed)

// split on a delimiter with getline
std::istringstream line("a,b,c");
std::string field;
while (std::getline(line, field, ','))   // field = "a", then "b", then "c"
    cols.push_back(field);

// BUILD: assemble a string with <<, then extract it
std::ostringstream oss;
oss << "id=" << 7 << ";n=" << 3;
std::string s = oss.str();    // "id=7;n=3"
💡 This is the everyday tokenizer "Split this CSV line / parse these numbers" is a stringstream job in C++. Keep this pattern handy — it shows up constantly in real code and interviews.

Source: cppreference — std::stringstream.

05 Formatting: the modern path

Stream formatting via manipulators is verbose and stateful:

#include <iomanip>
std::cout << std::fixed << std::setprecision(2) << std::setw(8) << price;   // clunky & sticky

Since C++20, prefer std::format (build a string) and C++23's std::print (write it straight out) — type-safe, positional, far cleaner:

#include <print>     // C++23
std::print("{:>8.2f}\n", price);          // width 8, 2 decimals — no sticky state
🎯 Rule of thumb Use streams for the plumbing (where bytes go: file, console, string). Use std::format/std::print for the formatting (how they look). One performance note: for heavy console output, std::ios::sync_with_stdio(false) speeds up cin/cout.

Source: cppreference — std::print (C++23).

06 Check yourself

What do << and >> do on a stream?
When does a std::ofstream close its file?
You need to split "3 14 159" into three ints. Reach for:
For clean, type-safe formatted output in modern C++, prefer:

07 Flashcards

Q: What is a stream?
A: A flow of characters you insert into with << or extract from with >>. The same model serves console, files, and in-memory strings.
Q: cin >> x vs getline?
A: >> reads one whitespace-delimited token and parses it; getline reads a whole line (spaces included). Mixing them needs an ignore() to drop the leftover newline.
Q: The idiomatic file read loop?
A: std::ifstream in(path); std::string line; while (std::getline(in, line)) { ... } — the stream is truthy until EOF/error, and closes itself (RAII).
Q: What's stringstream for?
A: A stream backed by a string — used to parse a line into typed fields (>> or getline with a delimiter) and to build a string piece by piece, then read it with .str().
Q: How do you check a stream succeeded?
A: A stream converts to bool: if (in) / if (cin >> x) is true while good, false after a failed read or EOF.
Q: Streams vs std::format — division of labor?
A: Streams handle where bytes go (the plumbing); std::format/std::print handle how they're formatted. Prefer the latter over manipulators.
👩‍🏫 I'm your teacher — ask me anything

Try: "write a CSV-line splitter with stringstream", or "why did my getline read a blank line after cin >>?" One lesson left — concurrency.