File I/O and Streams¶
Stream-based I/O (<fstream>, <iostream>) and filesystem operations (<filesystem>). RAII-managed file handles with automatic cleanup.
Key Facts¶
std::ifstream- input file stream (reading)std::ofstream- output file stream (writing)std::fstream- bidirectional file stream- Streams are RAII - file closed automatically in destructor
- Check state:
if (stream)orstream.good(),stream.fail(),stream.eof() std::getline(stream, string)reads entire linestream >> varextracts formatted data, skips whitespace- Binary I/O:
stream.read(),stream.write()withstd::ios::binaryflag <filesystem>(C++17): path manipulation, directory iteration, file operationsstd::filesystem::pathhandles OS-specific path separators- Prefer
<filesystem>over C-stylefopen/fcloseor OS-specific APIs
Patterns¶
Reading Files¶
#include <fstream>
// Read entire file to string
std::string read_file(const std::string& path) {
std::ifstream file(path);
if (!file) throw std::runtime_error("Cannot open: " + path);
return std::string(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>());
}
// Read line by line
void process_lines(const std::string& path) {
std::ifstream file(path);
std::string line;
while (std::getline(file, line)) {
// process line
}
}
// Read structured data
struct Record { std::string name; int age; double score; };
std::vector<Record> read_csv(const std::string& path) {
std::ifstream file(path);
std::vector<Record> records;
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
Record r;
char comma;
if (iss >> r.name >> comma >> r.age >> comma >> r.score) {
records.push_back(r);
}
}
return records;
}
Writing Files¶
// Text output
void write_report(const std::string& path,
const std::vector<Record>& data) {
std::ofstream file(path);
if (!file) throw std::runtime_error("Cannot create: " + path);
file << "Name,Age,Score\n";
for (const auto& r : data) {
file << r.name << ',' << r.age << ',' << r.score << '\n';
}
// file closed automatically
}
// Append mode
std::ofstream log("app.log", std::ios::app);
log << "Event occurred\n";
// Truncate (default for ofstream)
std::ofstream fresh("data.txt", std::ios::trunc);
Binary I/O¶
// Write binary
void save_binary(const std::string& path, const std::vector<float>& data) {
std::ofstream file(path, std::ios::binary);
size_t count = data.size();
file.write(reinterpret_cast<const char*>(&count), sizeof(count));
file.write(reinterpret_cast<const char*>(data.data()),
count * sizeof(float));
}
// Read binary
std::vector<float> load_binary(const std::string& path) {
std::ifstream file(path, std::ios::binary);
size_t count;
file.read(reinterpret_cast<char*>(&count), sizeof(count));
std::vector<float> data(count);
file.read(reinterpret_cast<char*>(data.data()),
count * sizeof(float));
return data;
}
Filesystem (C++17)¶
#include <filesystem>
namespace fs = std::filesystem;
// Path operations
fs::path p = "/home/user/docs/file.txt";
p.filename(); // "file.txt"
p.stem(); // "file"
p.extension(); // ".txt"
p.parent_path(); // "/home/user/docs"
p / "subdir"; // "/home/user/docs/file.txt/subdir"
// File operations
bool exists = fs::exists(p);
auto size = fs::file_size(p); // bytes
auto time = fs::last_write_time(p);
fs::copy("src.txt", "dst.txt");
fs::rename("old.txt", "new.txt");
fs::remove("temp.txt");
fs::create_directories("a/b/c"); // creates all intermediate
// Directory iteration
for (const auto& entry : fs::directory_iterator("/path")) {
if (entry.is_regular_file()) {
std::cout << entry.path() << " : " << entry.file_size() << '\n';
}
}
// Recursive iteration
for (const auto& entry : fs::recursive_directory_iterator("/path")) {
if (entry.path().extension() == ".cpp") {
process(entry.path());
}
}
Gotchas¶
- Issue: Not checking if file opened successfully -> silent failure, empty reads -> Fix: Always check
if (!file)after construction or use exceptions:file.exceptions(std::ios::failbit) - Issue: Mixing
>>andgetline->>leaves\nin buffer, nextgetlinereads empty -> Fix: Callstd::ignoreorgetlineto consume the newline before switching modes - Issue:
fs::remove_allcan follow symlinks on some platforms -> Fix: Check withfs::is_symlinkbefore recursive delete - Issue: Text mode on Windows adds
\r\n- corrupts binary data -> Fix: Always usestd::ios::binaryfor non-text files