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
- File Streams
- Opening and Closing Files
- Reading Files
- Writing Files
- Binary Files
- File Position
- 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