CSS Prepare

optional · CSS study notes

Files, Streams, and Exception Handling (extended, incl. Random Access Files)

  • Sequential access files: data read/written in order from beginning to end
  • Random access files: allows jumping directly to any position (e.g., via seekg()/seekp() in C++) without reading through preceding data
  • File processing modes: read, write, append, binary vs text mode
  • Exception Handling: try block (code that may throw an error) — catch block (handles the specific exception type) — throw (raises an exception) — enables graceful error recovery instead of abrupt program termination

File Open Mode Flags (fstream) — commonly tested

FlagMeaning
ios::inOpen for reading
ios::outOpen for writing
ios::appAppend — writes go to the end, existing content preserved
ios::ateOpen and immediately seek to the end (unlike app, you CAN seek elsewhere afterward)
ios::truncDiscard existing content on open (default with ios::out)
ios::binaryOpen in binary mode — required for raw struct/class I/O (.write/.read)

Sequential file write + read example

#include <fstream>
#include <iostream>
using namespace std;

int main()
{
    ofstream fout("data.txt");
    fout << "Hello CSS aspirant" << endl;
    fout.close();

    ifstream fin("data.txt");
    string line;
    getline(fin, line);
    cout << "Read back: " << line << endl;
    fin.close();
    return 0;
}

Exception handling example

#include <iostream>
using namespace std;

int divide(int a, int b)
{
    if (b == 0)
        throw runtime_error("Division by zero!");   // throw
    return a / b;
}

int main()
{
    try                                              // try block
    {
        cout << divide(10, 0) << endl;
    }
    catch (const runtime_error& e)                    // catch block
    {
        cout << "Caught exception: " << e.what() << endl;
    }
    return 0;
}

Output: Caught exception: Division by zero! — program continues instead of crashing.

Self-Test Questions

  1. What's the difference between ios::app and ios::ate?
  2. Why must ios::binary be used when writing raw structs/classes to a file?
  3. What happens to program flow when an exception is thrown but no matching catch exists?

Random Access Files — worked example (seekg / seekp)

#include <fstream>
#include <iostream>
using namespace std;

struct Record { int id; char name[10]; };

int main()
{
    // Write 3 fixed-size records
    ofstream fout("records.dat", ios::binary);
    Record r1 = {1, "Ali"}, r2 = {2, "Sara"}, r3 = {3, "Bilal"};
    fout.write((char*)&r1, sizeof(Record));
    fout.write((char*)&r2, sizeof(Record));
    fout.write((char*)&r3, sizeof(Record));
    fout.close();

    // Jump DIRECTLY to the 2nd record without reading the 1st
    fstream file("records.dat", ios::in | ios::out | ios::binary);
    file.seekg(1 * sizeof(Record), ios::beg);   // skip straight to record index 1
    Record r;
    file.read((char*)&r, sizeof(Record));
    cout << "Record 2: " << r.id << " " << r.name << endl;

    // Overwrite that same record in place
    r.id = 99;
    file.seekp(1 * sizeof(Record), ios::beg);   // move write pointer back to the same spot
    file.write((char*)&r, sizeof(Record));
    file.close();

    return 0;
}

Output: Record 2: 2 Sara

Key exam point: seekg() moves the read pointer, seekp() moves the write pointer — in a fstream opened for both, they're often used together, as shown here: read a record, modify it, then seek back to overwrite just that one record. This only works because every Record is a fixed size, so n * sizeof(Record) always lands exactly on record n's starting byte — the defining advantage of random access over sequential access.