- IO Stream
Published:
int sum_ints(std::istream& is) {
int i, sum = 0;
while (is >> i) { // extract a number to int i
sum += i;
std::cout << "current sum: " << std::setw(4) << sum;// 4 space, right align
print_io_states(is);
}
return sum;
}
Keeps printing the sum and stats
echo "5 7 9 " | ./io1
istream
while (is >> i);
istream& istream::operator>>(int& value); // modifies istream (this)
ios::operator bool() const;
// same as !ios::fail
- Return
istreamso can keep chaining things operator <type>is a conversion operation- Invoked when
<type>is required
- Invoked when
istreamis a base class ofiosstd::setw()is a function that returns an objectWidthManipulatorostream& operator<<(ostream& os, const WidthManipulator& wm) { os.width(wm.get_width()); return os; }
State
void print_io_states(std::ios& io) {
std::cout << '\t';
std::cout << " fail()==" << io.fail(); // bad + eof
std::cout << " bad()==" << io.bad();
std::cout << " eof()==" << io.eof();
std::cout << '\n';
}
Hierarchy
![[09-io-stream-hierarchy.svg]]
std::coutandstd::cinare instances ofostreamandistreamostingstreamprints into a stringofstreamprints into a fileiostateTop level
ios_basecontains flags and constants, such asios_base::iostate
iostate is a set of flags telling the state of the IO, can be combined
failbit: formatting/extraction error/EOFbadbit: irrecoverable error (E. disk crashed)- `eofbit
In class ios, flags can be accessed by:
fail()(failbitORbadbit)operator bool()same as!fail()
bad()eof()echo "10 2 3 4" | ./io1Only after summing
4, and trying to read for one more time, hits EOFechoadds a\nat the end of “4”.ioshits the\nfirst and parses the 4 okay
Now suppress \n by echo -n
echo -n "10 2 3 4" | ./io1
- Now, when summing “4”,
eof()set, since hit EOF directly after “4”fail() = 0,eof() = 1is >> istill evaluated to1, so loop executes one more time
- Last time,
fail() = 1,eof() = 1(still)
Error Recovery
Keep recovering until eof()
int sum_ints(std::istream& is) {
int i, sum = 0;
while (!is.eof()) {
is >> i; // skip all leading whitespaces
if (is.bad()) {
throw std::runtime_error{"bad istream"};
}
else if (is.fail()) { // fail(), but not bad()
if (is.eof()) {
// failbit && eofbit: this is normal (trailing whitespace)
break;
}
// failbit && !eofbit: probably non-digit; just skip it
is.clear();
char c;
is.get(c); // consume a single char
std::cout << " skipped: " << c << '\n';
}
else { // read i successfully;
// we could have hit eof or not (depends on trailing whitespace)
sum += i;
std::cout << "current sum: " << std::setw(4) << sum;
print_io_states(is);
}
}
return sum;
}
- If get
char, consume one character at a time - If get
int, consume a chunk
C vs Cpp
By default: std::cin is sync with stdin, and for out and err
- Cpp streams are unbuffered
- Each IO operation on cpp stream is immediately applied to the corresponding C stream’s buffer
- Underneath, call the C functions (E.
printf(),scanf())- Thin wrapper
Can detach Cpp stream from C stream, automatically add its own buffer:
std::ios_base::sync_with_stdio(false);
- Cpp streams are allowed to buffer its IO independently
- Lose the following:
- No longer thread-safe
- No
\nmay not flushstdoutto terminal- Use
'\n'instead ofstd::endlfor terminal output
- Use
- No longer thread-safe
Polymorphic ios
pair<T1, T2> is a library template with two types
void f1(istream& is) {
while (!is.eof()) {
is >> std::ws; // discard leading whitespace
if (!is || is.eof()) // break if nothing else
break;
pair<string,double> e;
is >> e; // overload >> to read from istream
if (is.fail())
break;
cout << e << '\n';
}
if (is.bad())
throw runtime_error{"bad istream"};
else if (is.fail()) // fail but not just eof
throw invalid_argument{"bad grade format"};
}
int main(int argc, char **argv) {
try {
f1(cin);
} catch (const exception& x) {
cerr << x.what() << '\n';
}
}
Now parse pair from istream:
std::istream& getline(std::istream& is, std::string& str, char delim);
static istream& operator>>(istream& is, pair<string,double>& e) {
char c;
// 1. read opening quote, skipping whitespace
if (is >> c && c == '"') {
string student;
// 2. read all chars into student, stop at closing quote, then discard it
if (std::getline(is, student, '"')) {
// 3. read a comma, skipping whitespace
if (is >> c && c == ',') {
double grade;
// 4. read double grade
if (is >> grade) {
e = make_pair(student, grade);
return is;
}
}
}
}
// if fall here, fail :(
is.setstate(ios_base::failbit);
return is;
}
static ostream& operator<<(ostream& os, const pair<string,double>& e) {
return os << "[" << e.first << "] (" << e.second << ")";
}
make_pair()
String Stream
Issue with f1(): one failed record failed will fail break and throw
- Want recover and move on
f2() adds another layer of buffer
- Read an entire line
- Construct
istringstreamobject from the line, as backup - Call
f1(iss)issbecomes theistreamsource off1(), instead ofcin- If error, print ```cpp void f2(istream& is) { string str;
while (std::getline(is, str)) { istringstream iss(str);
try { f1(iss); } catch (const invalid_argument& x) { cerr << x.what() << ": " << str << '\n'; } } } ```
File Stream
f3() constructs ifstream object
void f3(const char* filename) {
ifstream ifs { filename };
if (!ifs) {
if (filename != nullptr)
throw runtime_error{"can't open file: "s + filename};
else
throw runtime_error{"no file name provided"};
}
f2(ifs);
}
