Show Lecture.IO as a slide show.
CS253 I/O
Inclusion
For general I/O, you need to:
#include <iostream>
Use of fstream, ifstream, or ofstream requires:
#include <fstream>
Use of stringstream, istringstream, or ostringstream requires:
#include <sstream>
Use of I/O manipulators requires:
#include <iomanip>
I/O Class Hierarchy
I/O Class Hierarchy
or, if you prefer a diagram:
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
The △ indicates inheritance.
More
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
Methods & Operator Overloading
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
- What class defines
operator<<
?
- What class defines
operator>>
?
- What class defines
.open()
?
- What class defines
.get()
?
Multiple Inheritance
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
┌─────────┐ ┌──────────────┐
│ fstream │ │ stringstream │
└─────────┘ └──────────────┘
△ △
┌──────┴───────┐ ┌─────────┴────────┐
┌─────┴────┐ ┌───────┴──┐ ┌───────┴───────┐ ┌───────┴───────┐
│ ifstream │ │ ofstream │ │ istringstream │ │ istringstream │
└──────────┘ └──────────┘ └───────────────┘ └───────────────┘
What Header Files Define What
strange type?
Consider the error message from this bad code:
cout.zork(); // 🦡
c.cc:1: error: ‘std::ostream’ {aka ‘class std::basic_ostream<char>’}
has no member named ‘zork’
basic_ostream
Why!?
w-streams
- What’s a wchar_t? It’s a wide character.
- Despite its peculiar name, wchar_t is a fundamental type,
like char or int.
- Its purpose is to hold a wide character, like ñ, ⻥, or 🐟,
that doesn’t fit into a one-byte char.
- Usually identical to int, it can hold a Unicode code point,
an integer 0…144,000+.
Not a UTF-8 byte sequence—an integer code point.
char c = 'X';
wchar_t wc = L'⻥';
cout << sizeof(c) << '\n'
<< sizeof(wc) << '\n';
1
4
basic_whatever<type>
- How would my students have implemented all this? 💖 💖 💖
- After learning about templates, however, they would implement
the templated class basic_ostream, which takes either
char or wchar_t as a template argument.
Keep it DRY!
- Same for istream and string.
Unformatted output
We’re familiar with formatted I/O using <<
or >>
:
cout << "π ≈ " << 355/113.0 << endl;
π ≈ 3.14159
There’s also unformatted output:
cout.put('h');
cout.put('i');
char data[] = " there\nextra";
cout.write(data, 7);
hi there
Unformatted input
With unformatted input, you can read an arbitrary
number of bytes:
ifstream in("/etc/resolv.conf");
char buf[80];
in.read(buf, size(buf));
cout << "⊢";
cout.write(buf, in.gcount());
cout << "⊣";
⊢search cs.colostate edu colostate.edu
nameserver 129.82.45.181
nameserver 129.82⊣
istream::read() reads into a char buffer, which
is not '\0'
terminated.
char-based unformatted input
ifstream in("/etc/resolv.conf");
char c;
c = in.peek(); cout << "First: " << c << "\n";
c = in.get(); cout << "Again: " << c << "\n";
in.unget();
c = in.get(); cout << "Again: " << c << "\n";
c = in.get(); cout << "Second: " << c << "\n";
in.ignore(10000, '9');
while (in.get(c)) cout.put(c);
First: s
Again: s
Again: s
Second: e
.82.45.181
nameserver 129.82.103.78
nameserver 129.82.103.79
seek/tell
Diogenes
- An ostream has a put (write) pointer, an integer value that
keeps track of how far along in the output we are.
Similarly, an istream has a get (read) pointer.
p
= put (write), g
= get (read)
- You can query & change these:
ofstream out("xyz");
out.write("Hxllo there\n", 11);
out.seekp(1);
out.put('e');
out.close();
cout << ifstream("xyz").rdbuf();
Hello there
Only one
- Surprisingly, an fstream has only a single shared
put/get pointer, as opposed to one for input and one for output.
seek/tell methods
- tell ≡ ask a question about location
- seek ≡ change location
- g ≡ discuss the input (get) pointer
- p ≡ discuss the output (put) pointer
Misuse of .open()
ifstream and ofstream both inherited fstream::open():
const string home = getpwnam("cs253")->pw_dir;
ifstream in;
in.open(home+"/pub/ducks"); // 🦡
for (char c; in.get(c); )
cout << c;
Huey (red)
Dewey (blue)
Louie (green)
Why have that extra step? Just associate the filename at object construction:
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
for (char c; in.get(c); )
cout << c;
Huey (red)
Dewey (blue)
Louie (green)
Misuse of .eof()
- People who program by guesswork are often wrong about istream::eof().
- They think that it asks “Will the next read fail?”. It doesn’t.
- It asks “Did the previous read fail?”.
ifstream in("/etc/hostname");
string line;
while (!in.eof()) { // 🦡 BAD!
getline(in, line);
cout << "Data: " << line << '\n';
}
Data: beethoven
Data:
Where did that extra line come from?
It came from the second, failed, call to getline().
Nobody noticed the failure until the third call to .eof().
The right way to detect end-of-file
Don’t inquire in advance—just go ahead and read. It will succeed or fail:
ifstream in("/etc/hostname");
string line;
while (getline(in, line))
cout << line << '\n';
beethoven
Or, with fewer source lines and a reduced scope for line
:
ifstream in("/etc/hostname");
for (string line; getline(in, line); )
cout << line << '\n';
beethoven