CSS Prepare

optional · CSS study notes

18. Files & Streams

  • A stream is a sequence of bytes flowing between a program and a source/destination (file, console, etc.)
  • ifstream — input file stream (reading); ofstream — output file stream (writing); fstream — both
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
#include <fstream>
ofstream fout("data.txt");
fout << "Hello CSS aspirant" << endl;
fout.close();

Stream classes, laid out

ClassPurposeHeader
ifstreamInput file stream — reading from a file<fstream>
ofstreamOutput file stream — writing to a file<fstream>
fstreamBoth input and output on the same file<fstream>
cin/coutStandard input/output streams (console)<iostream>

Files and console I/O share the same <</>> operator syntax — this uniformity is intentional, part of the stream abstraction.

Opening, writing, and always closing

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

int main()
{
    ofstream fout("notes.txt");        // opens (creates if missing) for writing
    if (!fout)                          // ALWAYS check the stream opened successfully
    {
        cout << "Failed to open file!";
        return 1;
    }
    fout << "First line" << endl;
    fout << "Second line" << endl;
    fout.close();                       // always close -- flushes buffered data to disk

    return 0;
}

Open mode flags — combining with |

ofstream fout("log.txt", ios::app);              // append, don't overwrite
fstream file("data.dat", ios::in | ios::out | ios::binary);   // combine multiple flags
FlagMeaning
ios::inOpen for reading
ios::outOpen for writing
ios::appAppend — writes go to the end, existing content preserved
ios::ateOpen and seek to end immediately (but you CAN still seek elsewhere afterward)
ios::truncDiscard existing content on open
ios::binaryBinary mode — required for raw struct/class I/O

Important MCQs

  1. Which stream class is used for reading from a file?
    • a) ofstream b) ifstream c) sstream d) cout
  2. Which open-mode flag discards existing file content when opening?
    • a) ios::app b) ios::ate c) ios::trunc d) ios::binary
  3. Which flag is required for raw struct/class binary I/O?
    • a) ios::app b) ios::ate c) ios::trunc d) ios::binary
  4. ios::app differs from ios::ate in that:
    • a) They are identical b) ios::app always appends writes to the end; ios::ate seeks to the end once, but you can then seek elsewhere c) ios::ate is for reading only d) ios::app is binary only

Self-Test Questions

  1. Why should you always check if (!fout) after opening a file stream?
  2. What happens if you forget to call .close() on a file stream?
  3. What's the difference between ios::app and ios::ate?

📌 Sample & Repeated FPSC Questions (2016–2026)

2020, Paper I, Q5(b) (15 marks) — Write C++ programs to compute following: i. Add a student ii. Add a course iii. Find a student with respect to CGPA iv. Add a Teacher v. Update a student.

This is FPSC's flagship file-I/O question of the last decade, and it is already solved in full on the Classes and Objects — Exam Practice → "University Records System" page. From this page's Files & Streams angle, here's what it actually tests — the open-mode choice for each operation:

  • Add a student / course / teacher — ofstream opened with ios::app | ios::binary: appends a new record without disturbing existing ones.
  • Find a student by CGPA — ifstream opened with ios::binary, looping fin.read(...) until end-of-file: pure scanning, nothing is modified.
  • Update a student — a single fstream opened with ios::in | ios::out | ios::binary: needs both read and write on the same stream to locate, then overwrite, an existing record.
ofstream fout("students.dat", ios::app | ios::binary);   // "Add a student"
fout.write((char*)&s, sizeof(Student));

Records are written/read as raw binary structs (ios::binary) throughout, since text-mode <</>> cannot reliably round-trip a struct.

Exam angle: whenever FPSC gives a "design a class + persist it to file" prompt, the mode-flag choice (app vs in|out vs plain out) is worth as many marks as the class design itself — see this page's flag table above for the full reference.

📜 Past-Paper Questions & MCQs (CSS 2016–2026)

2020 · Paper-I · Q5(b) · 15 marks

Q. The university data is stored in files. Write C++ functions to (i) add a student, (ii) add a course, (iii) find a student by CGPA, (iv) add a teacher, (v) update a student.

Ans.

#include <iostream>
#include <fstream>
using namespace std;
struct Student { int id; char name[30]; int age; char address[40]; char contact[15]; char program[20]; float cgpa; };
struct Teacher { int id; char name[30]; int age; char address[40]; char degree[20]; char subjects[40]; float salary; };
struct Course  { char semester[10]; char code[10]; int studentId; int teacherId; char grade[3]; };

void addStudent() {                                   // (i)
    Student s;
    cout << "ID Name Age Address Contact Program CGPA: ";
    cin >> s.id >> s.name >> s.age >> s.address >> s.contact >> s.program >> s.cgpa;
    ofstream f("students.dat", ios::binary | ios::app);
    f.write((char*)&s, sizeof(s));
}
void addCourse() {                                    // (ii)
    Course c;
    cin >> c.semester >> c.code >> c.studentId >> c.teacherId >> c.grade;
    ofstream f("courses.dat", ios::binary | ios::app);
    f.write((char*)&c, sizeof(c));
}
void addTeacher() {                                   // (iv)
    Teacher t;
    cin >> t.id >> t.name >> t.age >> t.address >> t.degree >> t.subjects >> t.salary;
    ofstream f("teachers.dat", ios::binary | ios::app);
    f.write((char*)&t, sizeof(t));
}
void findByCGPA(float minCgpa) {                      // (iii)
    ifstream f("students.dat", ios::binary);
    Student s;
    while (f.read((char*)&s, sizeof(s)))
        if (s.cgpa >= minCgpa) cout << s.id << " " << s.name << " " << s.cgpa << endl;
}
void updateStudent(int id) {                          // (v)
    fstream f("students.dat", ios::binary | ios::in | ios::out);
    Student s;
    while (f.read((char*)&s, sizeof(s)))
        if (s.id == id) {
            cout << "New CGPA: "; cin >> s.cgpa;
            f.seekp(-(long)sizeof(s), ios::cur);      // go back one record
            f.write((char*)&s, sizeof(s));            // overwrite it
            break;
        }
}
  • Idea: records are stored as fixed-size structures in binary files. Adding appends a record, searching reads records in order, and updating moves the file pointer back one record with seekp and overwrites it.