CSC166 Object Oriented Programming

Object Oriented ProgrammingUnit 79 min read

File Handling & Streams: I/O, Exceptions, Random Access & File Errors

Unit 7 of Object Oriented Programming covers file handling in C++ using streams (ifstream/ofstream), exception handling for file errors, random access techniques, and practical applications like data persistence and error recovery. Learn how to read/write files, handle exceptions, and manage file operations efficiently

Key Concepts & Definitions

What is a Stream?

A stream is an abstract data type that represents a sequence of data elements. In C++, streams are used for input/output (I/O) operations. There are two main types:

  • Input Stream: Reads data from a source (e.g., keyboard, file).
  • Output Stream: Writes data to a destination (e.g., monitor, file).

Streams are object-oriented because they encapsulate I/O operations as methods of classes.

Hierarchy of Stream Classes

The stream class hierarchy in C++ is derived from the ios base class. Here’s a simplified hierarchy:

classDiagram
    class ios {
        <<abstract>>
        +virtual ~ios()
    }
    class istream : ios {
        +int get()
        +istream& operator>>(type&)
    }
    class ostream : ios {
        +ostream& operator<<(type)
        +void put(char)
    }
    class ifstream : istream {
        +ifstream(const char*)
        +ifstream& open(const char*)
    }
    class ofstream : ostream {
        +ofstream(const char*)
        +ofstream& open(const char*)
    }
    class fstream : istream, ostream {
        +fstream(const char*)
        +fstream& open(const char*, ios_base::openmode)
    }
    ios <|-- istream
    ios <|-- ostream
    istream <|-- ifstream
    ostream <|-- ofstream
    istream <|-- fstream
    ostream <|-- fstream

Common Stream Classes

Class Description
ifstream Input file stream (reads from files).
ofstream Output file stream (writes to files).
fstream File stream (both input and output).
istream Input stream (e.g., cin for keyboard input).
ostream Output stream (e.g., cout for monitor output).

File Handling in C++

Opening and Closing Files

To work with files, you must:

  1. Declare a stream object.
  2. Open the file using open() or the constructor.
  3. Perform I/O operations.
  4. Close the file using close().

Example: Writing to a File

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

int main() {
    ofstream outFile;          // Declare output file stream
    outFile.open("data.txt");  // Open file

    if (!outFile) {            // Check if file opened successfully
        cout << "Error opening file!" << endl;
        return 1;
    }

    outFile << "Hello, File Handling!" << endl;  // Write to file
    outFile.close();          // Close file
    return 0;
}

Example: Reading from a File

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

int main() {
    ifstream inFile;           // Declare input file stream
    inFile.open("data.txt");   // Open file

    if (!inFile) {             // Check if file opened successfully
        cout << "Error opening file!" << endl;
        return 1;
    }

    char line[100];
    while (inFile >> line) {   // Read line by line
        cout << line << endl;
    }
    inFile.close();            // Close file
    return 0;
}

Random Access in Files

Random access allows you to read/write data at any position in the file using seekg() (for input) and seekp() (for output). The position is specified using seekpos or seekg with offsets.

0123456789101112131415161718192021222324252627282930seekg(10)seekp(20)
Visualizing `seekg()` and `seekp()` positions in a file (0-based)

Example: Random Access

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

int main() {
    fstream file("data.txt", ios::in | ios::out);  // Open for read/write

    if (!file) {
        cout << "Error opening file!" << endl;
        return 1;
    }

    // Move to the 10th byte (0-based index)
    file.seekg(10);

    char ch;
    while (file.get(ch)) {    // Read from current position
        cout << ch;
    }

    file.close();
    return 0;
}

Exception Handling in File Operations

Exceptions handle errors like:

  • File not found.
  • Permission denied.
  • Disk full.

Example: Exception Handling

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

int main() {
    try {
        ifstream inFile("nonexistent.txt");
        if (!inFile) {
            throw runtime_error("File not found!");
        }
        char ch;
        while (inFile.get(ch)) {
            cout << ch;
        }
    }
    catch (const exception& e) {
        cerr << "Error: " << e.what() << endl;
    }
    return 0;
}

In the Real World

  1. eSewa (Nepal):

    • Uses file streams to store transaction records (e.g., electricity bills, tax payments). When a user pays a bill, the system writes the transaction details to a file for future reference. Random access is used to quickly retrieve specific records (e.g., a user’s payment history).
  2. Khalti (Nepal):

    • Employs file handling to log financial transactions securely. For example, when a user transfers money, the system writes the transaction details (sender, receiver, amount, timestamp) to a file. Exception handling ensures that if a file write fails (e.g., due to disk errors), the transaction is rolled back to prevent data loss.
  3. Daraz (Nepal):

    • Uses file streams to manage order queues. When a customer places an order, the system writes the order details to a file (e.g., orders.dat). Random access allows Daraz to quickly update an order’s status (e.g., "shipped," "delivered") without reading the entire file. Exception handling ensures that if a file operation fails, the order is not lost.

Worked Example: Student Records

Problem: Write a program to read student records from a file STD.DAT and display the names of students in class 5.

Assumptions:

  • STD.DAT contains records in the format: name,class.
  • Example content:
    Ram,5
    Shyam,7
    Hari,5
    

Solution:

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

struct Student {
    string name;
    int class_;
};

int main() {
    ifstream inFile("STD.DAT");
    if (!inFile) {
        cout << "Error opening file!" << endl;
        return 1;
    }

    Student s;
    while (inFile >> s.name >> s.class_) {
        if (s.class_ == 5) {
            cout << "Student in class 5: " << s.name << endl;
        }
    }
    inFile.close();
    return 0;
}

Trace:

Step s.name s.class_ Output
1 "Ram" 5 "Student in class 5: Ram"
2 "Shyam" 7 (No output)
3 "Hari" 5 "Student in class 5: Hari"

Comparison: File Modes

Mode Description
ios::in Open for input (default for ifstream).
ios::out Open for output (default for ofstream).
ios::app Append to the end of the file.
ios::trunc Truncate (clear) the file if it exists.
ios::binary Open in binary mode (for non-text files).
ios::ate Open at the end of the file.

Advantages and Disadvantages of File Handling

Advantages:

  • Persistence: Data remains stored even after the program terminates.
  • Reusability: Files can be read by multiple programs.
  • Efficiency: Large datasets can be handled without loading everything into memory.

Disadvantages:

  • Slower than memory operations: Disk I/O is slower than RAM access.
  • Error-prone: File operations can fail due to permissions, disk errors, etc.
  • Complexity: Managing file pointers and random access can be tricky.

Exam Tip

  1. Understand Stream Hierarchy: Know the inheritance between ios, istream, ostream, and file-specific classes (ifstream, ofstream, fstream).
  2. File Modes: Memorize common modes like ios::in, ios::out, ios::app, and ios::binary.
  3. Exception Handling: Always check if a file opened successfully and use try-catch for error handling.
  4. Random Access: Practice using seekg() and seekp() to navigate files.
  5. Operator Overloading: Be ready to overload >> and << for custom classes (e.g., Student).
  6. Real-World Scenarios: Relate file handling to applications like banking (transaction logs), e-commerce (order records), or government systems (citizen data).

flowchart TD
    A["Start"] --> B["Declare Stream Object"]
    B --> C["Open File"]
    C --> D{"File Open?"}
    D -->|"Yes"| E["Perform I/O"]
    D -->|"No"| F["Throw Exception"]
    E --> G["Close File"]
    G --> H["End"]
    F --> H

Based on the TU BSc CSIT syllabus for Object Oriented Programming (CSC166), unit 7.

Discussion

Loading…