Skip to content
C++

std::filesystem Quick Reference

C++17 std::filesystem cheatsheet — path operations, directory traversal, file queries, copy/rename/remove, permissions, and common patterns.

Path Construction

cpp
#include <filesystem>
namespace fs = std::filesystem;

fs::path p1 = "/usr/local/bin";
fs::path p2 = "data/config.json";
fs::path p3 = p1 / "clang";            // /usr/local/bin/clang
fs::path p4 = p2.parent_path();        // data
fs::path p5 = p2.filename();           // config.json
fs::path p6 = p2.stem();               // config
fs::path p7 = p2.extension();          // .json
fs::path p8 = p2.replace_extension(".yaml");

// Absolute / canonical
fs::path abs = fs::absolute(p2);       // prepend cwd
fs::path can = fs::canonical("/usr/../usr/local");  // /usr/local (resolves ..)
fs::path rel = fs::relative("/usr/local", "/usr");  // local

// String conversion
std::string  s = p1.string();          // native string
std::u8string u = p1.u8string();       // UTF-8
p1.generic_string();                   // forward slashes on all platforms

File and Directory Queries

cpp
fs::path p = "data/file.txt";

fs::exists(p)                // true/false
fs::is_regular_file(p)       // true if plain file
fs::is_directory(p)          // true if directory
fs::is_symlink(p)            // true if symlink
fs::is_empty(p)              // true if empty file or empty dir

fs::file_size(p)             // size in bytes (regular file only)
fs::last_write_time(p)       // fs::file_time_type

// Status
fs::file_status s = fs::status(p);
s.type()                     // file_type enum
s.permissions()              // perms bitmask

Directory Traversal

cpp
// Non-recursive
for (const auto& entry : fs::directory_iterator("src")) {
    std::println("{} ({})", entry.path().filename().string(),
                 entry.is_regular_file() ? entry.file_size() : 0);
}

// Recursive
for (const auto& entry : fs::recursive_directory_iterator(".")) {
    if (entry.path().extension() == ".cpp")
        std::println("{}", entry.path().string());
}

// With options: skip permission denied
fs::recursive_directory_iterator it{
    ".", fs::directory_options::skip_permission_denied};
for (const auto& entry : it) { /* ... */ }

// Collect all .hpp files
std::vector<fs::path> headers;
for (const auto& e : fs::recursive_directory_iterator("include"))
    if (e.extension() == ".hpp")
        headers.push_back(e.path());

Create, Copy, Move, Remove

cpp
// Create
fs::create_directory("output");           // error if parent missing
fs::create_directories("a/b/c");          // creates full path
fs::create_symlink("target", "link");

// Copy
fs::copy_file("src.txt", "dst.txt");                   // error if dst exists
fs::copy_file("src.txt", "dst.txt",
    fs::copy_options::overwrite_existing);             // overwrite ok
fs::copy("src_dir", "dst_dir",
    fs::copy_options::recursive);                      // copy directory tree

// Move / Rename
fs::rename("old.txt", "new.txt");  // atomic on POSIX if same filesystem

// Remove
fs::remove("file.txt");            // single file or empty dir
fs::remove_all("directory");       // recursive delete (like rm -rf)

Permissions

cpp
using perms = fs::perms;

fs::permissions("file.txt", perms::owner_read | perms::owner_write);

// Add execute permission
fs::permissions("script.sh",
    perms::owner_exec | perms::group_exec | perms::others_exec,
    fs::perm_options::add);

// Remove write permission
fs::permissions("readonly.txt", perms::owner_write,
    fs::perm_options::remove);

// Check
auto p = fs::status("file.txt").permissions();
bool owner_can_read = (p & perms::owner_read) != perms::none;

Temp Files and Directories

cpp
fs::path tmp = fs::temp_directory_path();   // /tmp on Linux, %TEMP% on Windows
// tmp: /tmp

// Create unique temp file (C++ doesn't have a portable mkstemp, use OS API)
// On POSIX:
char tmpl[] = "/tmp/myapp-XXXXXX";
int fd = mkstemp(tmpl);
fs::path tmpfile{tmpl};  // now you have the path

// Temp directory: create and delete automatically
struct TempDir {
    fs::path path;
    TempDir() : path{fs::temp_directory_path() / fs::path{std::to_string(std::rand())}} {
        fs::create_directory(path);
    }
    ~TempDir() { fs::remove_all(path); }
};

Error Handling

cpp
// Throwing overloads (default)
try {
    fs::copy_file("missing.txt", "dst.txt");
} catch (const fs::filesystem_error& e) {
    std::println("error: {} ({})", e.what(), e.path1().string());
}

// Non-throwing overloads — pass std::error_code
std::error_code ec;
fs::copy_file("missing.txt", "dst.txt", ec);
if (ec) std::println("failed: {}", ec.message());

// All functions have both overloads:
auto size = fs::file_size("file.txt", ec);
if (ec) { /* handle */ }

Common Patterns

cpp
// Find the project root (walk up to find CMakeLists.txt)
fs::path find_root(fs::path start) {
    for (auto p = fs::canonical(start); p != p.root_path(); p = p.parent_path())
        if (fs::exists(p / "CMakeLists.txt")) return p;
    throw std::runtime_error("project root not found");
}

// Ensure directory exists
void ensure_dir(const fs::path& p) {
    if (!fs::exists(p)) fs::create_directories(p);
}

// Atomic file write (write to temp, then rename)
void atomic_write(const fs::path& target, std::string_view content) {
    auto tmp = target;
    tmp += ".tmp";
    { std::ofstream f{tmp}; f << content; }
    fs::rename(tmp, target);  // atomic on POSIX
}
Edit on GitHub