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).