6 hours · 8 marks
A stream is an abstraction representing a flow of data (bytes) between a program and a device (console, file, memory). C++ I/O is built around a class hierarchy in <iostream>:
ios — base class holding common stream state/formatting flags.istream — handles input (cin, >>, get(), getline()).ostream — handles output (cout, <<, put()).iostream — inherits both istream and ostream for bidirectional streams.ifstream, ofstream, fstream (from <fstream>) — file input, file output, and bidirectional file streams respectively, derived from istream/ostream/iostream.Predefined objects: cin (standard input), cout (standard output), cerr (unbuffered standard error), clog (buffered standard error).
Each stream maintains state flags checked via member functions:
| Function | Meaning |
|---|---|
good() | No error flags set — stream is usable. |
eof() | End-of-file has been reached. |
fail() | A formatting or extraction error occurred (recoverable). |
bad() | A serious, likely unrecoverable I/O error occurred. |
clear() | Resets all error state flags. |
int x;
cin >> x;
if (cin.fail()) { cout << "Invalid input"; cin.clear(); }
Unformatted I/O works with raw characters/bytes without interpretation — e.g., get(), put(), getline(), read(), write().
Formatted I/O interprets data according to type and formatting rules, using >>/<< along with manipulators (setw, setprecision, fixed) to control width, precision, base, and alignment.
#include <iomanip>
cout << setw(10) << setfill('*') << 42 << endl; // formatted
cout << fixed << setprecision(2) << 3.14159 << endl; // 3.14
char ch;
cin.get(ch); // unformatted single character input
cout.put('A'); // unformatted single character output
The insertion (<<) and extraction (>>) operators can be overloaded for user-defined classes so objects can be directly written to/read from streams. Because the left operand is a stream object (ostream/istream), these MUST be overloaded as non-member (usually friend) functions.
class Point {
int x, y;
public:
Point(int a=0, int b=0): x(a), y(b) {}
friend ostream &operator<<(ostream &out, const Point &p) {
out << "(" << p.x << ", " << p.y << ")";
return out; // returning ostream& allows chaining: cout << p1 << p2;
}
friend istream &operator>>(istream &in, Point &p) {
in >> p.x >> p.y;
return in;
}
};
int main() {
Point p;
cin >> p;
cout << p;
}
File streams (from <fstream>) let a program read from or write to files on disk, using the same <</>> syntax as console I/O.
#include <fstream>
ofstream fout("data.txt"); // open for writing (creates/truncates file)
fout << "Hello File";
fout.close();
ifstream fin("data.txt"); // open for reading
string line;
getline(fin, line);
fin.close();
ofstream — derived from ostream, for writing to files.ifstream — derived from istream, for reading from files.fstream — derived from iostream, for both reading and writing.All three ultimately derive from the common base ios, inheriting formatting and error-state functionality.
| ASCII (text) file | Binary file |
|---|---|
| Data stored as human-readable characters | Data stored as raw bytes (memory representation) |
Opened without ios::binary (default text mode) | Opened with ios::binary flag |
| Larger file size, portable, editable with any text editor | Compact, faster I/O, but not human-readable |
Uses <</>> | Uses read()/write() |
ofstream fout("data.bin", ios::binary);
fout.write(reinterpret_cast<char*>(&obj), sizeof(obj));
struct Record { int id; char name[20]; };
Record r = {1, "Ram"};
ofstream fout("rec.dat", ios::binary);
fout.write((char*)&r, sizeof(r));
fout.close();
Record r2;
ifstream fin("rec.dat", ios::binary);
fin.read((char*)&r2, sizeof(r2));
fin.close();
Data is read/written in order from beginning to end, one record after another — simplest and most common access mode, suitable when records are always processed in order.
Allows jumping directly to any position in the file without reading everything before it, using file pointer manipulation functions (seekg/seekp) combined with fixed-size records.
fstream file("rec.dat", ios::in | ios::out | ios::binary);
file.seekg(2 * sizeof(Record)); // jump directly to the 3rd record (index 2)
file.read((char*)&r, sizeof(r));
seekg(pos) — moves the get (read) pointer to a position.seekp(pos) — moves the put (write) pointer to a position.tellg() — returns the current position of the read pointer.tellp() — returns the current position of the write pointer.ios::beg (from beginning), ios::cur (from current position), ios::end (from end) — e.g. file.seekg(-10, ios::end);ifstream fin("nofile.txt");
if (!fin) { cout << "File could not be opened"; } // uses overloaded operator!
if (fin.is_open()) { ... }
if (fin.fail()) { ... }
Instead of overloaded operators, file streams offer explicit member functions for finer control: open(), close(), is_open(), read(), write(), get(), put(), getline(), eof().
fstream f;
f.open("data.txt", ios::out);
if (f.is_open()) { f << "text"; f.close(); }
ios at the top, branching to istream and ostream; iostream inherits both; ifstream derives from istream, ofstream from ostream, fstream from iostream — see section 7.1.<< and >> operators for a user-defined class Complex. 7 marksComplex class with real and imaginary parts.seekg/seekp with fixed-size records to jump directly to any record's byte offset, giving direct O(1) access. See sections 7.9–7.11.#include <fstream>
#include <iostream>
using namespace std;
class Student { public: int roll; char name[20]; };
int main() {
Student s1 = {1, "Ram"};
ofstream fout("s.dat", ios::binary);
fout.write((char*)&s1, sizeof(s1));
fout.close();
Student s2;
ifstream fin("s.dat", ios::binary);
fin.read((char*)&s2, sizeof(s2));
fin.close();
cout << s2.roll << " " << s2.name;
}
<</>>; binary files store raw memory bytes, need the ios::binary flag and read()/write(), and are more compact but not human-readable.seekg(), seekp(), tellg(), and tellp() with examples. 5 marksseekg/tellg control/query the read (get) pointer position; seekp/tellp control/query the write (put) pointer position; both accept an optional direction flag (ios::beg, ios::cur, ios::end).get(), put(), read(), write()). Formatted I/O interprets data according to its type and applies formatting via manipulators like setw, setprecision, fixed, used with <</>>. See section 7.3.! operator or fail() after opening (file may not exist), is_open() to confirm a stream is currently attached to a file, eof() to detect end-of-file, and good()/bad() for overall/serious error checks. See section 7.12.