Filesystem
|
This section documents C++23 (ISO/IEC 14882:2024), as published by ISO/IEC JTC1/SC22/WG21 (wg21), verified against the freely available working draft N5046 (eel.is/c++draft) and cppreference.com. This content was generated with the assistance of AI and should be verified against the working draft and cppreference.com before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
C++17’s <filesystem> (modeled on Boost.Filesystem) provides a portable API for paths and file operations that
previously required OS-specific calls (stat, readdir, CreateFile, …).
std::filesystem::path
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path p = "/tmp/data/report.txt";
std::cout << p.parent_path() << '\n'; // "/tmp/data"
std::cout << p.filename() << '\n'; // "report.txt"
std::cout << p.stem() << '\n'; // "report"
std::cout << p.extension() << '\n'; // ".txt"
fs::path combined = fs::path("/tmp/data") / "report.txt"; // operator/ joins path segments
// portably (handles the separator)
std::cout << (combined == p) << '\n'; // 1 (true)
}
Creating, Copying, and Removing
#include <filesystem>
namespace fs = std::filesystem;
void demo() {
fs::create_directory("output");
fs::create_directories("output/nested/deep"); // creates every missing intermediate directory too
fs::copy_file("input.txt", "output/input.txt", fs::copy_options::overwrite_existing);
fs::rename("output/input.txt", "output/renamed.txt");
fs::remove("output/renamed.txt"); // removes one file/empty directory
fs::remove_all("output"); // removes a directory and everything inside it
}
File Properties
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void inspect(const fs::path& p) {
if (!fs::exists(p)) { std::cout << "missing\n"; return; }
std::cout << "size: " << fs::file_size(p) << " bytes\n";
std::cout << "is regular file: " << fs::is_regular_file(p) << '\n';
std::cout << "is directory: " << fs::is_directory(p) << '\n';
auto lastWrite = fs::last_write_time(p);
(void)lastWrite; // a std::chrono::time_point on the filesystem's own clock
}
Directory Iteration
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void listDirectory(const fs::path& dir) {
for (const auto& entry : fs::directory_iterator(dir)) { // one level only
std::cout << entry.path() << '\n';
}
for (const auto& entry : fs::recursive_directory_iterator(dir)) { // descends into subdirectories too
if (entry.is_regular_file()) std::cout << entry.path() << '\n';
}
}
Finding Files
#include <filesystem>
#include <vector>
namespace fs = std::filesystem;
std::vector<fs::path> findByExtension(const fs::path& dir, const std::string& ext) {
std::vector<fs::path> matches;
for (const auto& entry : fs::recursive_directory_iterator(dir)) {
if (entry.is_regular_file() && entry.path().extension() == ext) {
matches.push_back(entry.path());
}
}
return matches;
}
Error Handling with error_code
Every <filesystem> function has an overload taking a std::error_code& out-parameter, reporting failures
without throwing — useful when a missing file or permission error is an expected, recoverable outcome rather
than exceptional:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void safeRemove(const fs::path& p) {
std::error_code ec;
fs::remove(p, ec); // does NOT throw, even if p doesn't exist or can't be removed
if (ec) {
std::cout << "remove failed: " << ec.message() << '\n';
}
}
Without the error_code& overload, the same call throws fs::filesystem_error on failure — pick whichever
matches how "this operation might fail" fits the surrounding code (see
Error Handling for the general exceptions-vs-error-codes
trade-off).