Programs that forget everything when they close have limited uses. Saving high scores, loading a game level, reading a configuration file or processing a large data export all mean working with files.
C++ handles files with file streams from the <fstream> header. They work exactly like cin and cout, which you already know. You write to an ofstream with << and read from an ifstream with >> or getline. If you can read the keyboard and print to the screen, you can already read and write files.
In this lesson you'll create and append to files, read them word by word and line by line, check that files opened correctly, split CSV lines into fields with stringstream, and meet std::filesystem for working with paths and folders.
Writing with ofstream
#include <fstream>
ofstream out("scores.txt");
out << "Ana 82" << endl;
out << "Ben 91" << endl;- Creating an
ofstreamwith a file name opens the file for writing. If the file exists, it's emptied first. - To add to the end instead, open in append mode:
ofstream out("log.txt", ios::app);. <<writes text and numbers, just likecout.- The file is closed automatically when the stream object goes out of scope. You can also call
out.close()yourself.
Reading with ifstream
ifstream in("scores.txt");
string name;
int score;
while (in >> name >> score) {
cout << name << " scored " << score << endl;
}in >> valuereads one word or number at a time, skipping spaces and new lines.- The condition
while (in >> ...)keeps going until reading fails, which happens at the end of the file. - To read whole lines, including spaces, use
while (getline(in, line)).
Avoid the tempting while (!in.eof()): the end-of-file flag is only set after a read fails, so that loop usually processes the last line twice.
Checking for errors
Files might not exist, or you might not have permission to open them. Always check:
ifstream in("data.txt");
if (!in) {
cerr << "Could not open data.txt" << endl;
return 1;
}if (!in) or if (!in.is_open()) detects a failed open. cerr is the standard error stream, the right place for error messages. Returning a non-zero value from main tells the operating system the program failed.
Relative file names such as "data.txt" are looked up in the program's working directory, which in an IDE isn't always the folder you expect. If a file "can't be found", print the full path or use an absolute one to check.
Parsing lines and std::filesystem
A stringstream (from <sstream>) lets you read from a string as if it were a file. That's perfect for splitting a CSV line into fields:
stringstream fields(line);
string name, qty;
getline(fields, name, ','); // read up to the comma
getline(fields, qty, ',');getline with a third argument reads up to that character instead of a new line. Convert numeric fields with stoi and stod, as in the strings lesson.
Since C++17, <filesystem> handles paths and folders: filesystem::exists("data.txt"), filesystem::file_size(...) and filesystem::create_directory("output"). It's the modern way to check for files before opening them.
Open modes and reading a whole file
The second argument when you open a stream is the open mode. You can combine modes with |:
| Mode | Effect |
|---|---|
ios::out | Write. The default for ofstream; empties an existing file |
ios::app | Write, always adding at the end |
ios::in | Read. The default for ifstream |
ios::trunc | Empty the file when it opens |
ios::binary | Read or write bytes exactly, with no line-ending changes |
An fstream opened with ios::in | ios::out can both read and change an existing file without emptying it, but the open fails if the file doesn't exist yet. ios::binary matters most on Windows, where text mode turns \n into the two-character line ending \r\n on the way out and back again on the way in. Use it for images, saved game data and anything else that isn't plain text.
Sometimes you want a whole file in one string, for example to search it or hand it to a parser. Copy the stream's buffer into an ostringstream:
ifstream in("notes.txt");
ostringstream buffer;
buffer << in.rdbuf(); // copies the entire file
string all = buffer.str();rdbuf() gives access to the stream's underlying buffer, and sending it into another stream copies every byte, new lines included. This is fine for files of a few megabytes; for very large files, read and process one line at a time so memory stays small.
C++ Files Syntax
File stream syntax
#include <fstream>
#include <sstream>
ofstream out("file.txt"); // or ("file.txt", ios::app)
out << "text" << endl;
ifstream in("file.txt");
if (!in) { /* handle error */ }
string line;
while (getline(in, line)) { ... }
stringstream ss(line);
getline(ss, field, ',');C++ Files Summary
ofstreamwrites files (emptying them first); addios::appto append.ifstreamreads files with>>for words and numbers orgetlinefor whole lines.- Loop with
while (in >> x)orwhile (getline(in, line)), notwhile (!in.eof()). - Check
if (!in)after opening, and report problems oncerr. stringstreamandgetline(..., ',')split CSV lines;<filesystem>works with paths.
C++ Files Examples
Each example shows the code, the output it produces and what each part does.
Saving and loading high scores
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
{
ofstream out("scores.txt");
out << "Ana 82\n" << "Ben 91\n" << "Cleo 77\n";
}
ifstream in("scores.txt");
if (!in) {
cerr << "Can't open scores.txt" << endl;
return 1;
}
string name, best;
int score, top = -1;
while (in >> name >> score) {
if (score > top) { top = score; best = name; }
}
cout << "Best: " << best << " with " << top << endl;
return 0;
}Best: Ben with 91Line-by-line explanation
- Lines 7 to 10The braces end the ofstream's scope, which closes the file before we read it.
- Lines 13 to 16Check that the file opened before reading.
- Lines 20 to 22Read a name and a score on each pass until the file ends.
Appending to a log
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void logLine(const string& message) {
ofstream log("app.log", ios::app);
log << message << '\n';
}
int main() {
logLine("Program started");
logLine("Loaded 3 players");
logLine("Program finished");
ifstream in("app.log");
string line;
int n = 0;
while (getline(in, line)) {
cout << ++n << ": " << line << endl;
}
return 0;
}1: Program started
2: Loaded 3 players
3: Program finishedLine-by-line explanation
- Line 7ios::app opens the file for appending, so earlier lines are kept. (Run the program again and the log grows.)
- Line 8'\n' ends the line without forcing a flush, which is a little faster than endl.
- Lines 18 to 20getline reads each whole line, including spaces.
Totals from a CSV file
sales.csv contains three lines: pen,10,1.20, notebook,4,3.50 and lamp,1,24.50.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
int main() {
ifstream in("sales.csv");
string line;
double total = 0;
while (getline(in, line)) {
stringstream fields(line);
string item, qty, price;
getline(fields, item, ',');
getline(fields, qty, ',');
getline(fields, price, ',');
double lineTotal = stoi(qty) * stod(price);
total += lineTotal;
cout << left << setw(10) << item << fixed << setprecision(2) << lineTotal << endl;
}
cout << left << setw(10) << "TOTAL" << total << endl;
return 0;
}pen 12.00
notebook 14.00
lamp 24.50
TOTAL 50.50Line-by-line explanation
- Lines 14 to 18A stringstream over each line, split at the commas.
- Line 20Convert the text fields to numbers before doing maths.
- Line 22setw(10) pads the name, and fixed with setprecision(2) prints two decimals (from <iomanip>).
Common C++ Files Mistakes
Looping on eof()
while (!in.eof()) {
getline(in, line);
cout << line << endl; // the last line may print twice
}while (getline(in, line)) {
cout << line << endl;
}Not checking that the file opened
ifstream in("missing.txt");
in >> value; // silently fails; value is unchangedifstream in("missing.txt");
if (!in) { cerr << "Can't open missing.txt\n"; return 1; }
in >> value;Overwriting when you meant to append
ofstream log("app.log"); // empties the log every timeofstream log("app.log", ios::app);C++ Files in Real Projects
Files in C++ programs
Games save progress and load levels from files, scientific programs read huge data files and write results for analysis, and command-line tools process logs line by line. Larger programs often use formats such as JSON or binary files with dedicated libraries, but they're built on exactly the streams you used here.
C++ Files FAQ
How do I read a file into a vector of lines in C++?
Read with getline in a loop and add each line to the vector: while (getline(in, line)) lines.push_back(line);. The loop stops cleanly at the end of the file, and each stored line has its new line character removed. lines.size() then tells you how many lines the file had.
How do I write and read a binary file in C++?
Open the stream with ios::binary and use write and read, which work with raw bytes: out.write(reinterpret_cast<const char*>(&x), sizeof x); saves an int, and in.read(reinterpret_cast<char*>(&x), sizeof x); loads it back. This is fast, but the file depends on the machine's number sizes and byte order, and it doesn't work for types like std::string that hold pointers. For data you share, a text format is safer.
How do I delete or rename a file in C++?
Use <filesystem> (C++17): filesystem::remove("old.txt") deletes a file and returns true if something was removed, and filesystem::rename("a.txt", "b.txt") renames or moves it. rename throws filesystem::filesystem_error when it fails, for example if the file doesn't exist, so wrap it in try; remove simply returns false when there was nothing to delete.
How do I list all files in a folder in C++?
Loop over a filesystem::directory_iterator: for (const auto& entry : filesystem::directory_iterator("data")) cout << entry.path().filename().string() << endl;. Use recursive_directory_iterator to include subfolders, and entry.is_regular_file() to skip folders. Calling .string() prints the name without the quotes that printing a path directly adds.
Why is my file empty when I read it back straight after writing?
Writes are buffered, so text you send to an ofstream may still be in memory when another stream opens the same file. Close the writer first, either with out.close() or by letting it go out of scope at the end of a block, before you open the file for reading. out.flush() also pushes the pending text to the file without closing it.
C++ Files Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the code that writes a line to a file.
out("notes.txt");
out "Hello file" << endl;
Which mode adds to the end of an existing file?
A file contains 3 4 5. What does this print?
ifstream in("nums.txt");
int x, sum = 0;
while (in >> x) sum += x;
cout << sum;
Why is while (!in.eof()) a bad loop condition?
What does this print?
stringstream ss("red,green,blue");
string part;
getline(ss, part, ',');
getline(ss, part, ',');
cout << part;
C++ Files Quiz
5 questions to check what you learned.
Which header provides ifstream and ofstream?
- <iostream>
- <file>
- <stdio>
- <fstream>
What happens when you open an existing file with a plain ofstream?
- Its contents are erased first
- It's appended to
- An error occurs
- It opens read-only
How do you check that a file opened successfully?
- if (in == true)
- if (!in) or if (!in.is_open()) handles the failure
- in.check()
- It always opens
What is a stringstream useful for?
- Downloading files
- Encrypting text
- Sorting strings
- Reading from or writing to a string as if it were a stream, e.g. splitting a line
When is a file opened with an ofstream closed?
- Only when the program ends
- After every write
- When close() is called or the stream object goes out of scope
- Never automatically