C++ stream objects manage file handles through RAII: construction opens or associates a resource and destruction closes it. Check the stream state after opening and after important reads or writes; reaching end-of-file is different from a formatting or device failure.
The loop condition combines reading and success testing. A final bad state can distinguish normal end-of-file from an I/O failure.
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream input{"notes.txt"};
if (!input) {
std::cerr << "could not open notes.txt\n";
return 1;
}
std::string line;
for (int number = 1; std::getline(input, line); ++number)
std::cout << number << ": " << line << '\n';
if (!input.eof()) {
std::cerr << "read failed\n";
return 1;
}
}
For configuration or state, write a temporary file, flush and close it, then replace the target using filesystem behavior appropriate to the operating system. Direct truncation can destroy the old file before the new write succeeds.
Read with while (stream >> value) or while (std::getline(stream, line)) so processing occurs only after a successful extraction. Do not loop on !eof(), because eof is set only after a read attempts to pass the end and the body may process stale data.
For a replace-style update, write a complete temporary file, close and verify it, then replace the destination using filesystem operations with error handling. Text and binary modes can differ by platform. Never construct sensitive paths directly from untrusted input; resolve them under an allowed root.
Opening a stream and reading from it are separate operations with separate failure states. Check that the file opened before consuming data, perform extraction in the loop condition, and distinguish an expected end of file from malformed input or an I/O failure.
Avoid while (!stream.eof()). EOF becomes true only after a read attempts to pass the end, so that pattern can process stale data twice. Let getline or operator>> decide whether the next value exists.
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::istringstream input("alpha\nbeta");
std::string line;
int count = 0;
while (std::getline(input, line)) {
if (!line.empty()) ++count;
}
std::cout << count << '\n';
}
2
getline controls the loop and still returns the final line when the source has no trailing newline.
Try this next
0 of 2 completed
Test the stream with is_open() or its boolean state before reading or writing.
Formatted extraction leaves the newline in the stream. Consume it before calling getline.
Use it when bytes must be preserved exactly, such as images or a defined binary format.
Explore 500+ free tutorials across 20+ languages and frameworks.