14

Module 14: File I/O

Chapter 14 • Intermediate

45 min

File I/O

File I/O (Input/Output) allows programs to read from and write to files. It's essential for data persistence and working with external data.

File Streams

C++ uses streams for file operations:

  • `ifstream`: Input file stream (reading)
  • `ofstream`: Output file stream (writing)
  • `fstream`: File stream (both reading and writing)

Opening Files

Basic File Opening

cpp.js
#include <fstream>
using namespace std;

// Open for reading
ifstream inputFile("data.txt");

// Open for writing
ofstream outputFile("output.txt");

// Open for both
fstream file("data.txt", ios::in | ios::out);

File Modes

cpp.js
ios::in      // Open for reading
ios::out     // Open for writing
ios::app     // Append mode
ios::ate     // Seek to end on open
ios::trunc   // Truncate file (default for ofstream)
ios::binary  // Binary mode

Checking File Open

cpp.js
ifstream file("data.txt");
if (!file.is_open()) {
    cerr << "Cannot open file!" << endl;
    return 1;
}

// Or
if (!file) {
    cerr << "File error!" << endl;
}

Reading from Files

Reading Line by Line

cpp.js
ifstream file("data.txt");
string line;

while (getline(file, line)) {
    cout << line << endl;
}

Reading Word by Word

cpp.js
ifstream file("data.txt");
string word;

while (file >> word) {
    cout << word << " ";
}

Reading Character by Character

cpp.js
ifstream file("data.txt");
char ch;

while (file.get(ch)) {
    cout << ch;
}

Reading Numbers

cpp.js
ifstream file("numbers.txt");
int num;

while (file >> num) {
    cout << num << " ";
}

Writing to Files

Writing Text

cpp.js
ofstream file("output.txt");
file << "Hello, World!" << endl;
file << "Line 2" << endl;

Appending to Files

cpp.js
ofstream file("output.txt", ios::app);
file << "New line appended" << endl;

Writing Numbers

cpp.js
ofstream file("numbers.txt");
int num = 42;
double value = 3.14;

file << num << " " << value << endl;

File Position Operations

Getting File Position

cpp.js
ifstream file("data.txt");
streampos position = file.tellg();  // Get position

Setting File Position

cpp.js
file.seekg(0, ios::beg);  // Beginning
file.seekg(0, ios::end);  // End
file.seekg(10, ios::cur); // 10 bytes from current

File Status

Checking File State

cpp.js
ifstream file("data.txt");

if (file.good()) {
    // File is good
}

if (file.eof()) {
    // End of file reached
}

if (file.fail()) {
    // Operation failed
}

if (file.bad()) {
    // Serious error
}

Clearing File State

cpp.js
file.clear();  // Clear error flags

Binary File I/O

Writing Binary Data

cpp.js
ofstream file("data.bin", ios::binary);
int num = 42;

file.write(reinterpret_cast<const char*>(&num), sizeof(num));

Reading Binary Data

cpp.js
ifstream file("data.bin", ios::binary);
int num;

file.read(reinterpret_cast<char*>(&num), sizeof(num));

String Streams

String streams allow treating strings as streams:

cpp.js
#include <sstream>
using namespace std;

// String to number
string str = "42";
istringstream iss(str);
int num;
iss >> num;

// Number to string
ostringstream oss;
oss << 42;
string result = oss.str();

Best Practices

  1. Always check if file opened successfully
  2. Close files explicitly (or use RAII)
  3. Use RAII for automatic file closing
  4. Handle errors gracefully
  5. Use appropriate mode (text vs binary)
  6. Check file state after operations
  7. Use `getline` for reading lines
  8. Prefer string streams for in-memory operations

Common Patterns

Pattern 1: RAII File Wrapper

cpp.js
class FileReader {
    ifstream file;
public:
    FileReader(const string& filename) : file(filename) {
        if (!file.is_open()) {
            throw runtime_error("Cannot open file");
        }
    }
    ~FileReader() { file.close(); }
    ifstream& get() { return file; }
};

Pattern 2: Read Entire File

cpp.js
string readFile(const string& filename) {
    ifstream file(filename);
    ostringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

Common Mistakes

  • ❌ Not checking if file opened
  • ❌ Forgetting to close files
  • ❌ Not handling file errors
  • ❌ Using wrong file mode
  • ❌ Not checking file state
  • ❌ Mixing text and binary modes
  • ❌ Not using RAII for file management

Next Module

In Module 15, we'll learn about Concurrency and Multithreading - running multiple operations simultaneously in C++!

Hands-on Examples

Basic File Reading

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

int main() {
    // Create a sample file first
    {
        ofstream createFile("sample.txt");
        createFile << "Line 1: Hello, World!" << endl;
        createFile << "Line 2: C++ File I/O" << endl;
        createFile << "Line 3: Reading files" << endl;
    }
    
    cout << "=== Reading File Line by Line ===" << endl;
    ifstream file("sample.txt");
    
    if (!file.is_open()) {
        cerr << "Error: Cannot open file!" << endl;
        return 1;
    }
    
    string line;
    int lineNumber = 1;
    
    while (getline(file, line)) {
        cout << "Line " << lineNumber << ": " << line << endl;
        lineNumber++;
    }
    
    file.close();
    
    cout << "\n=== Reading File Word by Word ===" << endl;
    ifstream file2("sample.txt");
    string word;
    
    while (file2 >> word) {
        cout << word << " ";
    }
    cout << endl;
    
    file2.close();
    
    return 0;
}

Basic file reading uses ifstream. Check if file opened with is_open(). Use getline() to read line by line. Use >> operator to read word by word. Always close files when done. File automatically closes when stream object is destroyed.