Working with the File System in C++: From Basics to Advanced Techniques
Working with the file system is one of the fundamental tasks in C++ development. Whether it's saving application settings, processing logs, or creating complex data management systems — the ability to read, write, and manipulate files and directories is essential for every C++ developer. In this article, we will cover both the classic methods of working with files using fstream and the modern approach using the std::filesystem library (C++17 and newer).
Basics of Working with Files: The fstream Library
The fstream library (<fstream>) provides three main classes for working with files:
ifstream— for reading from a file (input file stream);ofstream— for writing to a file (output file stream);fstream— for both reading and writing.
Reading Data from a File
Let's look at a simple example of opening and reading a text file line by line:
#include <iostream>#include <fstream>#include <string>
int main() { std::ifstream inputFile("data.txt"); if (!inputFile.is_open()) { std::cerr << "Error opening file!" << std::endl; return 1; }
std::string line; while (std::getline(inputFile, line)) { std::cout << line << std::endl; }
inputFile.close(); return 0;}It is important to always check if the file was opened successfully using the is_open() method. The file will close automatically when it goes out of scope, but explicitly calling close() is considered good practice.
Writing Data to a File
Writing to a file is done similarly to console output — using the << operator:
#include <fstream>
int main() { std::ofstream outputFile("output.txt"); if (!outputFile) { std::cerr << "Failed to create file!" << std::endl; return 1; }
outputFile << "Line 1" << std::endl; outputFile << "Line 2" << std::endl; outputFile << 42 << std::endl; // numbers are automatically written as text
outputFile.close(); return 0;}By default, ofstream overwrites the file. To append data to the end, use the std::ios::app flag:
std::ofstream outputFile("log.txt", std::ios::app);Binary Files and Random Access
For working with binary data, use the std::ios::binary flag. The read() and write() methods allow you to work with memory blocks:
#include <fstream>
struct Record { int id; char name[50];};
int main() { // Writing a structure Record rec = {1, "Example"}; std::ofstream binOut("data.bin", std::ios::binary); binOut.write(reinterpret_cast<char*>(&rec), sizeof(rec)); binOut.close();
// Reading a structure Record recIn; std::ifstream binIn("data.bin", std::ios::binary); binIn.read(reinterpret_cast<char*>(&recIn), sizeof(recIn)); binIn.close();
return 0;}For positioning within a file, use seekg() (for input) and seekp() (for output) with the parameters std::ios::beg, std::ios::cur, or std::ios::end.
Modern C++: The std::filesystem Library
Starting with C++17, the std::filesystem module was added to the standard library, which significantly simplifies working with the file system. It provides convenient functions for manipulating paths, files, and directori