Every program we have written so far has shared one limitation: as soon as the program finishes running, every value stored in its variables, arrays, and objects disappears completely, since all of that data lives only in temporary memory. If you wanted to save a list of subscriber counts, video titles, or comment logs so that they still existed the next time the program ran, none of the tools we have covered so far would help with that.
File handling in C++ solves exactly this problem by allowing a program to read data from files stored on disk, and to write data into files that continue to exist even after the program has finished executing. This makes it possible to build programs that remember information between runs, process large sets of external data, or generate reports and logs that can be shared or reviewed later.
In this tutorial, you will learn how to use the fstream library to work with files in C++, including writing to files, reading from files, appending additional data, checking whether a file operation succeeded, and closing files properly once you are done with them.
File handling in C++ is made possible through the fstream library, which needs to be included at the top of a program before it can be used. This library provides three main classes: ofstream for writing to files, ifstream for reading from files, and fstream, which can handle both reading and writing.
| Class | Purpose |
|---|---|
| ofstream | Used for creating and writing data into a file. |
| ifstream | Used for opening and reading data from an existing file. |
| fstream | Used when both reading from and writing to the same file are required. |
Writing to a file in C++ involves creating an ofstream object, opening a file through it, sending data into the file using the insertion operator, exactly the same way cout is used for console output, and finally closing the file once writing is complete.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string channel = "CS Engineering Gyan";
ofstream outFile("subscribers.txt");
if (outFile.is_open()) {
outFile << channel << " subscriber log" << endl;
outFile << "Current subscribers: 60000" << endl;
outFile.close();
cout << "Data written to subscribers.txt successfully" << endl;
} else {
cout << "Unable to open file for writing" << endl;
}
return 0;
}
Data written to subscribers.txt successfully
Here, a file named subscribers.txt is either created if it does not already exist, or overwritten if it does, and two lines of text are written into it. Checking is_open() before writing is an important habit, since it confirms the file was actually opened successfully before any data is sent to it.
Reading data back out of a file follows a similar pattern, but uses an ifstream object instead. Data can be read line by line using the getline function, which is especially useful for text files containing full sentences or multiple words per line.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string channel = "CS Engineering Gyan";
ifstream inFile("subscribers.txt");
string line;
if (inFile.is_open()) {
cout << channel << " reading subscriber log:" << endl;
while (getline(inFile, line)) {
cout << line << endl;
}
inFile.close();
} else {
cout << "Unable to open file for reading" << endl;
}
return 0;
}
CS Engineering Gyan reading subscriber log: CS Engineering Gyan subscriber log Current subscribers: 60000
The while loop here continues running as long as getline successfully reads another line from the file, automatically stopping once the end of the file has been reached, without needing to know in advance how many lines the file actually contains.
By default, opening a file with ofstream overwrites any existing content inside it. If you want to add new data to a file without erasing what is already there, the file must be opened specifically in append mode.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string channel = "CS Engineering Gyan";
ofstream outFile("subscribers.txt", ios::app);
if (outFile.is_open()) {
outFile << "Milestone reached on: 6 August 2026" << endl;
outFile.close();
cout << channel << " milestone entry appended successfully" << endl;
} else {
cout << "Unable to open file for appending" << endl;
}
return 0;
}
CS Engineering Gyan milestone entry appended successfully
The second argument, ios::app, tells the file stream to place the writing position at the end of the existing file content, so any new data written joins the file rather than replacing what was already saved there.
C++ provides several file opening modes, which control exactly how a file should be treated when it is opened. These modes can also be combined together using the bitwise OR operator when more than one behavior is needed at once.
| Mode | Description |
|---|---|
| ios::in | Opens a file for reading data from it. |
| ios::out | Opens a file for writing data into it, creating it if it does not exist. |
| ios::app | Opens a file and places the writing position at the end, preserving existing content. |
| ios::trunc | Erases the existing content of a file if it already exists. |
| ios::binary | Opens a file in binary mode instead of the default text mode. |
Files are not limited to storing plain sentences of text. Numbers and multiple pieces of data can also be written into and read back from a file, using the same insertion and extraction operators used for console input and output.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string channel = "CS Engineering Gyan";
ofstream outFile("video_views.txt");
outFile << "Pointers Explained" << " " << 5200 << endl;
outFile << "Inheritance Basics" << " " << 3100 << endl;
outFile.close();
ifstream inFile("video_views.txt");
string title;
int views;
cout << channel << " video report:" << endl;
while (inFile >> title >> views) {
cout << title << " - " << views << " views" << endl;
}
inFile.close();
return 0;
}
CS Engineering Gyan video report: Pointers - 5200 views
It is worth noticing an important detail here: since the extraction operator reads data separated by whitespace, a multi-word title like "Pointers Explained" gets split apart during reading, which is why only "Pointers" appears alongside its number in the output, while "Explained" and everything after it gets misread. This demonstrates why plain whitespace-separated reading works well for single-word values, but requires more careful handling, such as using a delimiter or getline, when dealing with multi-word text fields.
When reading data from a file, especially in a loop, it is often useful to check whether the end of the file has been reached, so the program knows exactly when to stop attempting to read further data.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
string channel = "CS Engineering Gyan";
ifstream inFile("subscribers.txt");
string line;
if (inFile.is_open()) {
cout << channel << " full log until end of file:" << endl;
while (!inFile.eof()) {
getline(inFile, line);
if (!line.empty()) {
cout << line << endl;
}
}
inFile.close();
}
return 0;
}
CS Engineering Gyan full log until end of file: CS Engineering Gyan subscriber log Current subscribers: 60000 Milestone reached on: 6 August 2026
The eof() function returns true once the reading position has moved past the last piece of data in the file, allowing the loop to stop cleanly instead of attempting to read data that no longer exists.
Every file that is opened should eventually be closed using the close function, once the program is finished reading from or writing to it. Closing a file ensures that any data still waiting to be written is properly saved, and frees up the resources the operating system had reserved for that file.
While C++ will typically close files automatically when a file stream object goes out of scope, relying on this behavior in larger programs is not considered good practice, since explicitly closing a file makes the intent of the code clearer and avoids potential issues in more complex programs.
| Advantages | Limitations |
|---|---|
| Allows data to persist even after a program has finished running. | File operations depend on external factors like disk access and file permissions. |
| Makes it possible to process large datasets stored outside the program itself. | Reading and writing files is generally slower than working with data already in memory. |
| Useful for generating logs, reports, and reusable saved data. | Improper handling of file paths or modes can lead to lost or overwritten data. |
| Mistake | Correct Practice |
|---|---|
| Forgetting to check if a file was successfully opened before using it. | Always use is_open() to confirm the file opened correctly before reading or writing. |
| Opening a file with ofstream and losing existing data unintentionally. | Use ios::app when the goal is to preserve existing content and only add new data. |
| Assuming eof() becomes true before the final read attempt is made. | Check for successful reads directly in the loop condition instead of relying only on eof(). |
| Never closing a file after finishing work with it. | Always call close() once all file operations are complete. |
File handling extends a C++ program's reach beyond temporary memory, allowing data to be saved permanently, revisited later, or shared across different runs of a program. Using the fstream library, we saw how ofstream handles writing, ifstream handles reading, and how file modes like append control exactly how existing content is treated.
We also looked at practical concerns like checking whether a file opened successfully, detecting the end of a file while reading, and understanding how whitespace-separated reading can behave unexpectedly with multi-word text. Together, these tools make it possible to build programs that interact meaningfully with real, persistent data rather than values that vanish the moment the program ends.
This chapter completes our journey through the core building blocks of C++, from basic syntax and data types all the way through Object Oriented Programming and file handling. With this foundation in place, you are well equipped to explore more advanced C++ topics, build complete projects, and apply these concepts confidently in both academic and real-world programming.