K2A-B1-23
C++ Filesystem
Created 2018-07-10Updated 2026-02-28programming-language-stack / c_or_cpp / language
- Description: A note on
std::filesystem(C++17) —path, queries, traversal, file operations, error handling, and cross-platform considerations - My Notion Note ID: K2A-B1-23
- Created: 2018-07-10
- Updated: 2026-02-28
- License: Reuse is very welcome. Please credit Yu Zhang and link back to the original on yuzhang.io
Table of Contents
- 1.
std::filesystem::path - 2. Queries: Existence, Type, Size, Time
- 3. Iterating Directories
- 4. File Operations
- 5. Error Handling
- 6. Cross-Platform Considerations
1. std::filesystem::path
std::filesystem::path(C++17,<filesystem>) — filesystem location type. Handles encoding, separators, decomposition uniformly across platforms.
#include <filesystem>
namespace fs = std::filesystem;
fs::path p = "/var/log/app.log";
p.string(); // "/var/log/app.log"
p.filename(); // "app.log"
p.stem(); // "app"
p.extension(); // ".log"
p.parent_path(); // "/var/log"
p.replace_extension(".bak"); // "/var/log/app.bak"
// Composition with /= and /
fs::path dir = "/var/log";
fs::path file = dir / "app.log"; // "/var/log/app.log"
file /= "rotated"; // "/var/log/app.log/rotated"
// /= treats both sides as directory parts
- Path arithmetic (
/,/=) handles platform separator automatically. Don't concat strings manually.
2. Queries: Existence, Type, Size, Time
namespace fs = std::filesystem;
fs::path p = "/etc/hosts";
fs::exists(p); // true
fs::is_regular_file(p); // true
fs::is_directory(p); // false
fs::is_symlink(p); // false
fs::is_empty(p); // false (file is non-empty)
fs::file_size(p); // size in bytes (regular files only)
auto t = fs::last_write_time(p); // file_clock time_point
auto s = fs::status(p); // permissions + type (cached)
auto perms = s.permissions(); // permission bits
status(p)= cheapest single-stat. Boolean helpers (is_directory(p)) re-stat each call. In tight loops -> cache:
auto s = fs::status(p);
if (fs::is_regular_file(s)) { /* ... */ } // reuses the cached status
3. Iterating Directories
namespace fs = std::filesystem;
// Non-recursive
for (const auto& entry : fs::directory_iterator{"/var/log"}) {
std::cout << entry.path() << "\n";
}
// Recursive
for (const auto& entry : fs::recursive_directory_iterator{"/var/log"}) {
if (entry.is_regular_file()) {
std::cout << entry.path() << " (" << entry.file_size() << ")\n";
}
}
- Directory iterators yield
directory_entrys — cache file status for cheap repeated queries.
4. File Operations
namespace fs = std::filesystem;
// Create
fs::create_directory("/tmp/foo");
fs::create_directories("/tmp/foo/bar/baz"); // mkdir -p
// Copy / move
fs::copy("a.txt", "b.txt");
fs::copy("src/", "dst/", fs::copy_options::recursive | fs::copy_options::overwrite_existing);
fs::rename("old.txt", "new.txt");
// Remove
fs::remove("file.txt"); // single file
fs::remove_all("/tmp/foo"); // recursive (returns count)
// Symlinks
fs::create_symlink("/var/log/app.log", "current.log");
fs::read_symlink("current.log"); // "/var/log/app.log"
// Permissions
fs::permissions("script.sh", fs::perms::owner_exec, fs::perm_options::add);
5. Error Handling
- Every filesystem function has 2 overloads:
- Throws
std::filesystem::filesystem_erroron failure. - Takes
std::error_code&— reports failure through it, no throw.
namespace fs = std::filesystem;
// Throwing version
try {
auto sz = fs::file_size("missing.txt");
} catch (const fs::filesystem_error& e) {
std::cerr << e.what() << " path: " << e.path1() << "\n";
}
// Non-throwing version
std::error_code ec;
auto sz = fs::file_size("missing.txt", ec);
if (ec) {
std::cerr << "error: " << ec.message() << "\n";
}
- Pick whichever fits your error-handling style. See C++ Error Handling § 6.
6. Cross-Platform Considerations
- Encoding — POSIX:
char(typically UTF-8). Windows:wchar_t(UTF-16).path::native()= platform-native;path::string()converts (lossy on Windows for non-Latin filenames — usepath::u8string()for UTF-8). - Separators — use
/in literals;pathtranslates as needed. Don't hardcode backslashes on Windows. - Case sensitivity — POSIX = case-sensitive; Windows + macOS HFS+/APFS = case-insensitive, case-preserving. Don't rely on case-only differences.
- Permissions — POSIX
permsmap cleanly; Windows ACLs don't.permissions()API is approximate on Windows. - Symbolic links — Windows requires admin/dev mode; may fail otherwise.