READMEC++

README

Advanced Topics / File Handling

Concept Lesson
Intermediate
4 min

Learning Objective

Understand Advanced Topics well enough to explain it, recognize it in C++, and apply it in a small task.

Why It Matters

This concept is part of the foundation that later lessons and projects assume you already understand.

TopicsTable Of ContentsFile StreamsOpening And Closing FilesOpen Modes
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

README
2 min read18 headings

File Handling in C++

File handling connects C++ programs to persistent data. The key mental model is that a file stream behaves like cin or cout, but its source or destination is a file on disk. ifstream reads, ofstream writes, and fstream can do both when opened with the right mode.

Always decide three things before opening a file: whether you are reading or writing, whether the content is text or binary, and what should happen if the file already exists. Those choices determine the stream type and open flags.

Table of Contents

  1. File Streams
  2. Opening and Closing Files
  3. Reading Files
  4. Writing Files
  5. Binary Files
  6. File Position
  7. Best Practices

File Streams

#include <fstream>

// Input file stream
ifstream inputFile;

// Output file stream
ofstream outputFile;

// Input/Output file stream
fstream file;

Opening and Closing Files

Open Modes

// Open for reading
ifstream in("file.txt");
ifstream in2("file.txt", ios::in);

// Open for writing (creates/truncates)
ofstream out("file.txt");
ofstream out2("file.txt", ios::out);

// Append
ofstream app("file.txt", ios::app);

// Binary mode
ifstream bin("file.bin", ios::binary);

// Read and write
fstream rw("file.txt", ios::in | ios::out);

// Truncate existing
ofstream trunc("file.txt", ios::trunc);

Check and Close

ifstream file("data.txt");

// Check if open
if (file.is_open()) {
    // Use file
}

// Check for errors
if (!file) {
    cerr << "Failed to open file" << endl;
}

// Close explicitly (also happens in destructor)
file.close();

Reading Files

Read Line by Line

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

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

Read Word by Word

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

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

Read Character by Character

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

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

Read Entire File

#include <sstream>

ifstream file("data.txt");
stringstream buffer;
buffer << file.rdbuf();
string content = buffer.str();

// Or using iterators
ifstream file2("data.txt");
string content2((istreambuf_iterator<char>(file2)),
                 istreambuf_iterator<char>());

Read Formatted Data

ifstream file("data.txt");
int id;
string name;
double score;

// File: 1 Alice 95.5
while (file >> id >> name >> score) {
    cout << id << " " << name << " " << score << endl;
}

Writing Files

Write Text

ofstream file("output.txt");

file << "Hello, World!" << endl;
file << "Line 2" << endl;

// With formatting
file << fixed << setprecision(2) << 3.14159 << endl;

Append to File

ofstream file("log.txt", ios::app);
file << "New log entry" << endl;

Write Formatted Data

ofstream file("data.txt");

struct Person {
    int id;
    string name;
    double score;
};

vector<Person> people = {{1, "Alice", 95.5}, {2, "Bob", 87.3}};

for (const auto& p : people) {
    file << p.id << " " << p.name << " " << p.score << endl;
}

Binary Files

Write Binary

ofstream file("data.bin", ios::binary);

int num = 42;
file.write(reinterpret_cast<char*>(&num), sizeof(num));

// Write array
int arr[] = {1, 2, 3, 4, 5};
file.write(reinterpret_cast<char*>(arr), sizeof(arr));

// Write struct
struct Data { int x; double y; };
Data d = {10, 3.14};
file.write(reinterpret_cast<char*>(&d), sizeof(d));

Read Binary

ifstream file("data.bin", ios::binary);

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

// Read array
int arr[5];
file.read(reinterpret_cast<char*>(arr), sizeof(arr));

// Read struct
Data d;
file.read(reinterpret_cast<char*>(&d), sizeof(d));

File Position

Get Position

ifstream file("data.txt");

// Get current position
streampos pos = file.tellg();  // g = get
// For output: file.tellp();   // p = put

Set Position

fstream file("data.txt", ios::in | ios::out);

// Seek from beginning
file.seekg(0, ios::beg);

// Seek from current position
file.seekg(10, ios::cur);

// Seek from end
file.seekg(-5, ios::end);

// Seek to specific position
file.seekg(100);

Get File Size

ifstream file("data.bin", ios::binary | ios::ate);
streamsize size = file.tellg();
file.seekg(0, ios::beg);

Best Practices

Learner Notes

Treat file I/O as an operation that can fail. The file may not exist, the path may be wrong, the process may not have permission, or the disk may be full. A good program checks the stream state before trusting the data. For beginner programs, if (!file) after opening is enough; in production code, return a clear error or throw an exception with the path included.

Text files are best for logs, configuration, and data a human may inspect. Binary files are useful when speed or exact memory layout matters, but they require more care because structure padding, endianness, and version changes can make old files hard to read.

Practice by writing a small score table to scores.txt, reading it back into a vector, and then repeating the exercise in binary form. Compare the code and explain which version would be easier to debug six months later.

✅ Do

// 1. Use RAII - file closes automatically
{
    ofstream file("data.txt");
    file << "content";
}  // File closed here

// 2. Check if file opened successfully
ifstream file("data.txt");
if (!file) {
    throw runtime_error("Cannot open file");
}

// 3. Use getline for lines with spaces
string line;
getline(file, line);

// 4. Use string stream for parsing
string line = "1,Alice,95.5";
stringstream ss(line);
string token;
while (getline(ss, token, ',')) {
    cout << token << endl;
}

❌ Don't

// 1. Don't forget to check file state
// file >> data;  // What if file failed?

// 2. Don't mix >> and getline carelessly
int n;
file >> n;        // Leaves newline
getline(file, s); // Gets empty line!

// Fix: consume newline
file >> n;
file.ignore();    // Or file.ignore(numeric_limits<streamsize>::max(), '\n');
getline(file, s);

// 3. Don't use binary I/O for classes with pointers
// They contain addresses, not data

Quick Reference

// Open modes
ios::in      // Read
ios::out     // Write
ios::app     // Append
ios::binary  // Binary
ios::trunc   // Truncate
ios::ate     // At end

// Read operations
file >> var           // Formatted input
getline(file, str)    // Read line
file.get(ch)          // Read char
file.read(buf, n)     // Binary read

// Write operations
file << var           // Formatted output
file.put(ch)          // Write char
file.write(buf, n)    // Binary write

// Position
file.tellg() / tellp()   // Get position
file.seekg(n) / seekp(n) // Set position

// State
file.is_open()        // Check if open
file.eof()            // End of file
file.fail()           // Operation failed
file.good()           // No errors
file.clear()          // Clear error flags

Compile & Run

g++ -std=c++17 -Wall examples.cpp -o examples && ./examples

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue