iostream formatting
A file stream is std::cout with a file behind it: std::ofstream writes, std::ifstream reads, and both take the same operators and manipulators as the terminal streams of lesson 066.
The stream closes the file in its destructor, which is the RAII pattern of lesson 027 in the standard library. What a program has to add is the check that the file opened, and the choice between overwriting and appending.
A file that is written and read by the same process needs a flush or a close between the two, because the read opens the file separately and sees only what reached the disk. The stream's destructor is the usual close, and a scope around the writing part is the usual way to get one.
Writing a text file
std::ofstream opens the file for writing and truncates it if it exists. The << operator writes text exactly as it does to std::cout, and the newline is a character in the file.
The program writes two lines and prints a marker. The cat command then shows the file, which is the proof that the text reached disk and that the stream closed at the end of main.
The stream buffers its output and flushes when the buffer is full, when it is closed, or when the program ends. A crash before the flush loses the buffer, which is why a program that must not lose a line calls flush or closes the file.
#include <fstream>
#include <iostream>
int main()
{
std::ofstream out{"lines.txt"};
out << "first line\n";
out << "second line\n";
std::cout << "wrote two lines\n";
}
g++ -std=c++23 -Wall -Wextra write.cpp -o write
./write
cat lines.txt
wrote two lines
first line
second line
Reading with getline
std::getline reads one line at a time, without the newline, and returns the stream. The loop while (std::getline(in, line)) runs until the end of the file, and the last read that fails leaves the stream in a state that ends the loop.
The program writes three numbers, reads them back and sums them. std::stoi converts each line, and the print shows 60.
Reading line by line is the right default for text: it keeps the structure of the file and it does not care about spaces inside a line. Reading with >> is for a file whose fields are separated by whitespace.
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ofstream{"data.txt"} << "10\n20\n30\n";
std::ifstream in{"data.txt"};
std::string line;
int sum = 0;
while (std::getline(in, line)) {
sum += std::stoi(line);
}
std::cout << sum << '\n';
}
g++ -std=c++23 -Wall -Wextra read.cpp -o read_file
./read_file
60
Appending
The second argument of the constructor is a mode. std::ios::app opens the file for writing at the end, so the existing content stays and the new text follows it.
The program writes one line, closes the stream and opens the same file in append mode for a second line. The cat command shows both, in the order they were written.
The other common mode is std::ios::binary, which turns off the newline translation that text mode does on some systems. Lesson 068 uses it for raw bytes.
#include <fstream>
#include <iostream>
int main()
{
{
std::ofstream out{"log.txt"};
out << "start\n";
}
std::ofstream more{"log.txt", std::ios::app};
more << "more\n";
std::cout << "appended\n";
}
g++ -std=c++23 -Wall -Wextra append.cpp -o append
./append
cat log.txt
appended
start
more
Checking that the file opened
Constructing an ifstream on a path that does not exist does not throw by default: the stream opens in a failed state and every read does nothing. The program has to ask.
The program tries to open a missing file and prints is_open(). The answer is 0, and a program that ignored it would read no lines and report success.
The fix is a check after the constructor, with an error message or an exception. std::ifstream has an exceptions() setting that turns a failed open into a throw, which lesson 077 covers.
#include <fstream>
#include <iostream>
int main()
{
std::ifstream in{"missing.txt"};
std::cout << in.is_open() << ' ' << static_cast<bool>(in) << '\n';
}
g++ -std=c++23 -Wall -Wextra open.cpp -o open_check
./open_check
0 0
The missing header
The file stream types live in <fstream>. Including only <iostream> leaves std::ofstream an unknown name, and the compiler reports that it is not a member of std.
The program uses std::ofstream with <iostream> included. The error names the type and the namespace, and the fix is one include, which the compiler cannot suggest because the type was never declared.
The same message appears for std::stringstream without <sstream> and for std::setprecision without <iomanip>, so a missing include is worth recognising from the shape of the error.
#include <iostream>
int main()
{
std::ofstream out{"x.txt"};
out << "text\n";
}
g++ -std=c++23 -Wall -Wextra no_fstream.cpp -o no_fstream
no_fstream.cpp: In function 'int main()':
no_fstream.cpp:5:19: error: variable 'std::ofstream out' has initializer but incomplete type
5 | std::ofstream out{"x.txt"};
| ^~~
no_fstream.cpp:2:1: note: 'std::ofstream' is defined in header '<fstream>'; this is probably fixable by adding '#include <fstream>'
1 | #include <iostream>
+++ |+#include <fstream>
2 |
Exercises
- Write ten lines to a file, read them back and print the longest one.
- Append a timestamp line to a log file three times and print the file.
- Open a file that does not exist and print a message from the program instead of reading nothing.
Questions
A new set of questions in a new order every time. Choose one answer for each, then check.
-
Which type writes to a file?
Answer
std::ofstream
The o stands for output, and the stream opens the file in its constructor.
-
When is a file stream closed?
Answer
In its destructor, or by an explicit close
The destructor closes the file, which is the RAII pattern in the library.
-
How do you check that a file opened?
Answer
Test the stream in a condition
The stream's bool conversion reports the open state.
-
What does
std::getlineread?Answer
One line up to the newline
The function stops at the delimiter and does not store it.
-
What does this program print and write?
#include <fstream> #include <iostream> int main() { { std::ofstream out{"lines.txt"}; out << "first line\n" << "second line\n"; } std::cout << "wrote two lines\n"; std::ifstream in{"lines.txt"}; std::string line; while (std::getline(in, line)) std::cout << line << '\n'; }Answer
wrote two lines / first line / second line
The writer closes at the end of the block, and the reader prints the two lines back.
-
What does this program print?
#include <fstream> #include <iostream> int main() { { std::ofstream out{"numbers.txt"}; out << "10\n20\n30\n"; } std::ifstream in{"numbers.txt"}; int value = 0, total = 0; while (in >> value) total += value; std::cout << total; }Answer
60
The extraction reads the three numbers, and their sum is 60.
-
What does this program print and leave in the file?
#include <fstream> #include <iostream> int main() { { std::ofstream out{"log.txt"}; out << "start\n"; } { std::ofstream out{"log.txt", std::ios::app}; out << "more\n"; } std::ifstream in{"log.txt"}; std::string line; while (std::getline(in, line)) std::cout << line << ' '; }Answer
start more
The second stream opens in append mode, so the second line follows the first.
-
What does this program print?
#include <fstream> #include <iostream> int main() { std::ifstream missing{"does-not-exist.txt"}; std::cout << static_cast<bool>(missing) << ' '; std::ofstream out{"here.txt"}; std::cout << static_cast<bool>(out); }Answer
0 1
The missing file fails to open and the new file opens for writing.
-
What does the compiler report for this line?
#include <iostream> int main() { std::ofstream out{"x.txt"}; out << "text"; }Answer
variable 'std::ofstream out' has initializer but incomplete type
The type is only declared without <fstream>, and the note names the header.
-
Why does an ofstream truncate the file by default?
Answer
The default open mode is out, which truncates
Passing std::ios::app or std::ios::in changes the default.
The code on this page was built with g++ 15.2.0 and run on Alpine Linux 3.24.3 (x86_64) in a Docker container. The programs whose section shows a compiler error were compiled until that error and were not run.
Article author: Arthur Isaev