Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

4.4 File I/O — Modes, Methods, Pointers & Random Access

Lesson 22 of 22 in the free Object Oriented Programming with C++ notes on Siksha Sarovar, written by Rohit Jangra.

4.4 File I/O — Modes, Methods, Pointers & Random Access

File I/O in C++

File operations use the <fstream> header and three classes:

ClassDirectionHeader
ofstreamOutput to file (write)<fstream>
ifstreamInput from file (read)<fstream>
fstreamBoth directions<fstream>
#include <fstream>
using namespace std;

---

Opening and Closing Files

Two ways to open

// Method 1: constructor
ofstream fout("output.txt");

// Method 2: open() method
ofstream fout;
fout.open("output.txt");

Always close

fout.close();

If you don't close, the destructor will close — but explicit close() is cleaner and lets you check for errors immediately.

Checking if open succeeded

ofstream fout("output.txt");
if (!fout) {                       // or: if (!fout.is_open())
    cout << "Cannot open file";
    return 1;
}

---

File Open Modes

ModeConstantDescription
inios::inOpen for reading (default for ifstream)
outios::outOpen for writing (default for ofstream)
appios::appAppend — write at end
ateios::ateAt-end — start position at end, but allow random write
truncios::truncTruncate to zero length if exists
binaryios::binaryBinary mode (no text translation)

Modes can be combined with | (bitwise OR):

ofstream fout("data.bin", ios::out | ios::binary | ios::app);
fstream  ff("file.txt",   ios::in | ios::out);

Common combinations

Use caseMode
Read text fileifstream f("file.txt"); (default in)
Write new text file (overwrite)ofstream f("file.txt"); (default `outtrunc`)
Append to text fileofstream f("file.txt", ios::app);
Read + write text`fstream f("file.txt", ios::inios::out);`
Read binaryifstream f("file.bin", ios::binary);
Write binaryofstream f("file.bin", ios::binary);

---

Writing to a Text File

#include <fstream>
using namespace std;

int main() {
    ofstream fout("students.txt");

    if (!fout) {
        cout << "Cannot open file";
        return 1;
    }

    fout << "Rohit Jangra" << " " << 101 << " " << 88.5 << "\n";
    fout << "Priya Sharma" << " " << 102 << " " << 92.3 << "\n";
    fout << "Amit Kumar"   << " " << 103 << " " << 75.0 << "\n";

    fout.close();
    cout << "Data written";
    return 0;
}

Reading from a Text File

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

int main() {
    ifstream fin("students.txt");

    if (!fin) {
        cout << "Cannot open file";
        return 1;
    }

    string name1, name2;
    int    id;
    double marks;

    while (fin >> name1 >> name2 >> id >> marks) {     // assuming "First Last id marks"
        cout << name1 << " " << name2 << " " << id << " " << marks << "\n";
    }

    fin.close();
    return 0;
}

Reading Line-by-Line

ifstream fin("data.txt");
string line;
while (getline(fin, line)) {
    cout << line << endl;
}

---

Binary File I/O

For non-text data — structs, integers, raw bytes — use binary mode with write() / read():

struct Student {
    int id;
    char name[50];
    float marks;
};

int main() {
    Student s1 = {101, "Rohit", 88.5};

    // Write
    ofstream fout("students.dat", ios::binary);
    fout.write(reinterpret_cast<char*>(&s1), sizeof(s1));
    fout.close();

    // Read
    Student s2;
    ifstream fin("students.dat", ios::binary);
    fin.read(reinterpret_cast<char*>(&s2), sizeof(s2));
    cout << s2.id << " " << s2.name << " " << s2.marks;
    fin.close();
    return 0;
}
Binary mode preserves bytes exactly. Text mode may translate \n\r\n on Windows. For non-text, always use binary.

---

File Pointers and Random Access

Streams maintain two pointers:

PointerPurpose
get pointer (tellg/seekg)Position for reading
put pointer (tellp/seekp)Position for writing

Get pointer functions

FunctionPurpose
fin.tellg()Get current read position
fin.seekg(pos)Set absolute read position
fin.seekg(offset, direction)Set relative read position

Put pointer functions

FunctionPurpose
fout.tellp()Get current write position
fout.seekp(pos)Set absolute write position
fout.seekp(offset, direction)Set relative write position

Seek directions

ConstantFrom
ios::begBeginning of file
ios::curCurrent position
ios::endEnd of file

Examples

fin.seekg(0, ios::beg);    // rewind to beginning
fin.seekg(0, ios::end);    // jump to end
int size = fin.tellg();     // get file size

fin.seekg(100);             // jump to byte 100
fin.seekg(-50, ios::end);   // jump to 50 bytes before end
fin.seekg(20, ios::cur);    // skip 20 bytes ahead

---

Random Access — Reading the Nth Record

For fixed-size records, random access is direct:

struct Student {
    int id;
    char name[50];
    float marks;
};

int main() {
    fstream fs("students.dat", ios::in | ios::out | ios::binary);

    // Read student #5 (zero-indexed)
    int recordNum = 4;
    fs.seekg(recordNum * sizeof(Student));

    Student s;
    fs.read(reinterpret_cast<char*>(&s), sizeof(s));
    cout << "Student 5: " << s.id << " " << s.name << endl;

    // Update student #5's marks
    s.marks = 95.0;
    fs.seekp(recordNum * sizeof(Student));
    fs.write(reinterpret_cast<char*>(&s), sizeof(s));

    fs.close();
    return 0;
}

This is the classic fixed-length-record database pattern — used in legacy systems, embedded systems, and high-performance I/O.

---

Sequential vs Random Access

AspectSequential AccessRandom Access
Reading orderBeginning to endAny position
Best forLogs, text streamsDatabases, indexed files
File formatVariable-length linesFixed-length records
Position knowledgeNot neededRequired
Functions>>, getline, readseekg, seekp + read/write

---

File State Checking

FunctionReturns true if
fin.good()No errors
fin.eof()End of file reached
fin.fail()Format error or EOF
fin.bad()Stream corrupted
fin.is_open()File is open
if (fin)Not fail and not bad
ifstream fin("nofile.txt");
if (!fin.is_open()) {
    cout << "File not opened";
}

---

Error Handling During File Operations

ifstream fin("data.txt");
if (!fin) {
    cout << "Error: cannot open input file";
    return 1;
}

// Try reading; check for failure
int x;
fin >> x;
if (fin.fail()) {
    if (fin.eof()) cout << "Reached end of file";
    else cout << "Read error";
}

Modern: use exceptions

ifstream fin("data.txt");
fin.exceptions(ifstream::failbit | ifstream::badbit);

try {
    int x;
    fin >> x;
}
catch (const ifstream::failure& e) {
    cout << "I/O error: " << e.what();
}

---

Persistent Objects

A persistent object is one whose state survives beyond a program run — saved to disk and re-loaded.

class Account {
    int id;
    char name[50];
    double balance;
public:
    Account() = default;
    Account(int i, const char* n, double b) : id(i), balance(b) {
        strncpy(name, n, 50);
    }

    // Save object to file
    void save(ofstream& fout) {
        fout.write(reinterpret_cast<char*>(this), sizeof(Account));
    }

    // Load object from file
    void load(ifstream& fin) {
        fin.read(reinterpret_cast<char*>(this), sizeof(Account));
    }

    void display() {
        cout << id << " " << name << " ₹" << balance << endl;
    }
};

int main() {
    Account a(1, "Rohit", 50000);

    ofstream fout("accounts.dat", ios::binary);
    a.save(fout);
    fout.close();

    Account b;
    ifstream fin("accounts.dat", ios::binary);
    b.load(fin);
    fin.close();

    b.display();      // 1 Rohit ₹50000
    return 0;
}

Limitations of direct serialisation:

  • Works only for POD types (no pointers, no virtual functions, no string)
  • Not portable (endianness, struct padding)
  • For real applications, use JSON / XML / Protocol Buffers / SQLite

---

Command Line Arguments

C++ programs receive command-line arguments via main's parameters:

int main(int argc, char* argv[]) {
    cout << "Program name: " << argv[0] << endl;
    cout << "Argument count: " << argc << endl;

    for (int i = 1; i < argc; i++) {
        cout << "Arg " << i << ": " << argv[i] << endl;
    }
    return 0;
}
$ ./program hello world 42
Program name: ./program
Argument count: 4
Arg 1: hello
Arg 2: world
Arg 3: 42

Standard parameters:

  • argc (argument count) — number of arguments including program name
  • argv (argument vector) — array of C-style strings
  • argv[0] is the program name

Use case — file copy

int main(int argc, char* argv[]) {
    if (argc != 3) {
        cout << "Usage: " << argv[0] << " <source> <dest>" << endl;
        return 1;
    }

    ifstream src(argv[1], ios::binary);
    ofstream dst(argv[2], ios::binary);

    if (!src || !dst) {
        cout << "Cannot open files";
        return 1;
    }

    dst << src.rdbuf();      // efficient one-line copy
    cout << "Copied " << argv[1] << " to " << argv[2];
    return 0;
}
$ ./copy input.txt output.txt

---

Complete Example — Student Records Database

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

struct Student {
    int  id;
    char name[50];
    float marks;
};

void writeStudents(const string& filename, Student arr[], int n) {
    ofstream fout(filename, ios::binary);
    if (!fout) { cout << "Write failed"; return; }
    fout.write(reinterpret_cast<char*>(arr), n * sizeof(Student));
    fout.close();
}

void readAllStudents(const string& filename) {
    ifstream fin(filename, ios::binary);
    if (!fin) { cout << "Read failed"; return; }

    Student s;
    while (fin.read(reinterpret_cast<char*>(&s), sizeof(s))) {
        cout << s.id << " " << s.name << " " << s.marks << endl;
    }
    fin.close();
}

Student readNthStudent(const string& filename, int n) {
    ifstream fin(filename, ios::binary);
    fin.seekg(n * sizeof(Student));        // random access
    Student s;
    fin.read(reinterpret_cast<char*>(&s), sizeof(s));
    fin.close();
    return s;
}

void updateNthStudent(const string& filename, int n, const Student& s) {
    fstream fs(filename, ios::in | ios::out | ios::binary);
    fs.seekp(n * sizeof(Student));
    fs.write(reinterpret_cast<const char*>(&s), sizeof(s));
    fs.close();
}

int main() {
    Student arr[3] = {
        {101, "Rohit", 88.5f},
        {102, "Priya", 92.3f},
        {103, "Amit",  75.0f}
    };

    writeStudents("students.dat", arr, 3);
    readAllStudents("students.dat");
    cout << "---" << endl;

    Student s = readNthStudent("students.dat", 1);   // student #2
    cout << "Student 2: " << s.id << " " << s.name << endl;

    s.marks = 99.9f;
    updateNthStudent("students.dat", 1, s);

    readAllStudents("students.dat");
    return 0;
}

---

Study deep

  1. Text vs binary mode matters on Windows. Text mode translates \n to \r\n on write and back on read. Use binary for non-text data, or to preserve exact bytes.
  1. **reinterpret_cast<char>(&obj) is the standard idiom for binary I/O.* Treats any object as a byte array. Safe for POD types; unsafe for objects with pointers / virtual functions.
  1. File pointers tellg/tellp may differ. fstream opened in read+write mode has separate get and put positions — they can diverge.
  1. Modern serialisation libraries. For real-world apps, use JSON (nlohmann/json), XML (pugixml), Protocol Buffers, MessagePack instead of raw binary. They handle versioning, types, portability.
  1. std::filesystem (C++17). Modern file/path operations:
#include <filesystem>
namespace fs = std::filesystem;
fs::path p("data.txt");
if (fs::exists(p)) cout << "Size: " << fs::file_size(p);

Key Terms — Lesson 4.4

The terms below cover C++ file I/O — every PYQ on file streams, modes, pointers, or random access expects fluent use.

<fstream> Header — The C++ standard header that declares the file stream classesifstream (input), ofstream (output), fstream (both). Required for any file I/O the C++ way.

ifstream — The input file stream class — for reading from a file. Constructor opens the file; destructor closes it (RAII). Derives from istream, so it inherits all the >>, getline, get, read operations.

ofstream — The output file stream class — for writing to a file. Constructor opens (creating or truncating); destructor closes. Derives from ostream, inheriting <<, put, write.

fstream — The bidirectional file stream — for both reading and writing the same file. Derives from iostream. Useful for in-place file updates and random-access patterns.

File Open Mode — A bitmask flag passed to a file stream's constructor or open() controlling how the file is opened. Combined with |. Common modes: ios::in (read), ios::out (write), ios::app (append), ios::ate (open and seek to end), ios::trunc (truncate if exists), ios::binary (binary mode).

ios::in — Open for input (reading). Default for ifstream. File must exist; otherwise the stream's fail bit is set.

ios::out — Open for output (writing). Default for ofstream. File is created if missing and truncated (emptied) if it exists, unless ios::app or ios::ate is also specified.

ios::app (Append Mode) — Open for output with appending only — every write goes to the current end of file, regardless of seek position. Existing content is preserved.

ios::ate ("at end") — Open and immediately seek to the end of the file, but subsequent writes can be at any position the program seeks to. Different from app (which forces every write to end).

ios::trunc — Open for output and discard existing contents. Default behaviour for ofstream when not specified. Combined with ios::out for explicit truncation.

ios::binary (Binary Mode) — Open in binary mode — no text translation (no \n\r\n conversion on Windows). Essential for non-text data (images, serialised structs); recommended for cross-platform reliability even for text where exact byte preservation matters.

Text Mode vs Binary Mode — Two file-open modes with subtle but important differences. Text mode (default) performs line-ending translation on Windows (\n\r\n). Binary mode transmits bytes exactly as written/read. Use binary for non-text data and for cross-platform compatibility.

open() Method — A file-stream method that opens a file after the stream is constructed: ifstream fin; fin.open("data.txt");. Equivalent to passing the filename to the constructor. Useful for reusing a stream variable across multiple files.

close() Method — A file-stream method that closes the file, flushing buffers and releasing the OS file handle. Called automatically by the destructor (RAII), so explicit close() is rarely needed — but useful when reopening the same stream for a different file.

is_open() Method — A method that returns true if the file was opened successfully, false otherwise. Standard pattern: if (!fin.is_open()) { / error handling / }.

File Pointer / Position — The current read/write position inside the file, measured in bytes from the beginning. Every stream tracks its position; reading or writing advances it.

Get Pointer vs Put Pointer — Input streams have a get pointer (read position). Output streams have a put pointer (write position). fstream opened for both has both pointers independently.

seekg() / seekp() — Methods that move the get / put pointer to a specified position. seekg(pos) moves to absolute byte position; seekg(offset, direction) moves relative to ios::beg (beginning), ios::cur (current), or ios::end (end of file).

tellg() / tellp() — Methods that return the current get / put pointer position as a streampos. Useful for recording the position to seek back to later.

Random Access — The ability to read or write any position in the file in any order, not just sequentially. Achieved with seekg/seekp to position the pointer and read/write to perform the operation. Required for fixed-record-size databases where you compute byte offsets and jump directly.

Fixed-Length Record — A binary file layout where each record occupies the same number of bytes, allowing direct access to the N-th record at offset N × recordSize. The pre-database approach to flat-file storage; still useful for embedded systems and high-performance binary files.

read() Method — A method that reads up to N raw bytes from a stream into a buffer: fin.read(buffer, N); or fin.read(reinterpret_cast<char*>(&obj), sizeof(obj));. The byte-level counterpart of >>. Returns the stream; fin.gcount() reports how many bytes were actually read.

write() Method — A method that writes N raw bytes from a buffer to a stream: fout.write(buffer, N); or fout.write(reinterpret_cast<char*>(&obj), sizeof(obj));. The byte-level counterpart of <<.

Binary I/O Idiom — The standard pattern for reading/writing structs in binary form: fout.write(reinterpret_cast<char*>(&obj), sizeof(obj));. Safe for POD (Plain Old Data) types; unsafe for objects containing pointers, virtual functions, or non-trivial members (their addresses don't survive serialisation).

POD (Plain Old Data) — A type that has the same memory layout as a C struct — no virtual functions, no constructors that initialise members non-trivially, no inheritance. POD types can be safely serialised with write/read of raw bytes. Modern C++ replaces POD with the more nuanced concept of trivially-copyable types.

End of File (EOF) — The condition reached when all data in the file has been read. Indicated by the stream's eof flag. The idiomatic read loop: while (fin >> value) exits cleanly when EOF or read error occurs.

Command Line Arguments — Parameters passed to a program at invocation, received by main(int argc, char* argv[]). argc is the count (always ≥ 1); argv is the array of C-strings, with argv[0] being the program name and argv[1..argc-1] the user-supplied arguments.

rdbuf() — A method that returns the stream's underlying stream buffer. dst << src.rdbuf(); is the fastest way to copy one stream to another because it bypasses character-by-character processing.

std::filesystem (C++17) — The modern standard library for file and directory operations beyond simple I/O — path manipulation, existence/size queries, directory iteration, file copying and removal. #include <filesystem> and std::filesystem::exists(p) / file_size(p) / copy(src, dst).

Serialisation — The process of converting in-memory objects to a sequence of bytes for storage or transmission. Binary file I/O is the most direct form; modern serialisation libraries (nlohmann/json, Protocol Buffers, MessagePack, Cap'n Proto) handle versioning, types, and cross-platform compatibility.

File Stream Failure Modes — Common errors: file does not exist (open fails for input), permission denied, disk full, broken pipe. Always check is_open() after opening; check the stream's truthiness after each operation; handle failures explicitly rather than assuming success.

---

PYQ pattern (very common): "Write a C++ program to read from and write to a file." — Use ifstream / ofstream; show open, check open, write/read with << / >>, close; mention modes.
PYQ pattern: "Explain file pointers and random access in C++ files." — Two pointers (get + put); seekg / seekp with positions and directions; example of accessing N-th record.
PYQ pattern: "What are command line arguments? Explain with example." — int main(int argc, char* argv[]); argc = count, argv = array of strings; argv[0] = program name; example file-copy program.
PYQ pattern: "Explain file open modes in C++." — Table 6 modes (in, out, app, ate, trunc, binary); show combinations with |; common use cases per mode.