[2026] C++ std::filesystem Complete Guide | Cross-Platform Path, Directory, File Operations [#37-1]
이 글의 핵심
Master C++ std::filesystem: cross-platform paths, directory iteration, file operations, permissions, error handling, and production patterns.
Introduction: “Works on Linux, Breaks on Windows”
ifstream Opens on Linux but Not Windows
I wrote code to read config file config/settings.json. It works fine on Linux and macOS, but only on Windows I get “file not found” error.
Cause: Path separators differ. Linux/macOS use /, Windows uses \. Hardcoding "config/settings.json" with / usually works on Windows too, but when combining paths with string concatenation like path + "/" + filename, mixing with config\settings.json causes problems. Bigger issue: confusing executable-relative path vs working directory-relative path.
Solution: C++17 std::filesystem’s path automatically converts to OS-appropriate separator, and operator/ safely combines paths.
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ❌ Bad: string concatenation
std::string configPath = baseDir + "/config/settings.json";
// ✅ Good: std::filesystem::path
#include <filesystem>
namespace fs = std::filesystem;
fs::path configPath = fs::path(baseDir) / "config" / "settings.json";
std::ifstream file(configPath);
After reading this:
- Handle cross-platform paths with
std::filesystem::path. - Traverse directories, copy/delete/move files.
- Check and set file permissions.
- Know common errors and production patterns.
Table of Contents
- Problem Scenarios
- std::filesystem Overview
- Path Operations
- Directory Iteration
- File Operations
- Permissions
- Common Errors and Solutions
- Best Practices
- Production Patterns
- Checklist
- Summary
Analogy
Time, files, logs, JSON are frequently-used wrenches in the toolbox. Standardizing with validated libraries lets the entire team align on same units, same formats.
1. Problem Scenarios
Scenario 1: Program Crashes Because Log Directory Doesn’t Exist
Problem: Trying to write to logs/app.log, but if logs folder doesn’t exist, ofstream open fails.
Solution: Use std::filesystem::create_directories() to create parent directories first.
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
void ensureLogDir(const fs::path& logPath) {
fs::path dir = logPath.parent_path();
if (!dir.empty() && !fs::exists(dir)) {
fs::create_directories(dir);
}
}
int main() {
fs::path logPath = "logs/app.log";
ensureLogDir(logPath);
std::ofstream log(logPath);
log << "Application started\n";
}
Scenario 2: Scan Plugin Folder for .so/.dll Files Only
Problem: Need to load only dynamic libraries from plugins/, but .txt, .md files are mixed in.
Solution: Use directory_iterator to traverse and filter by path.extension().
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
#include <vector>
namespace fs = std::filesystem;
std::vector<fs::path> findPlugins(const fs::path& pluginDir) {
std::vector<fs::path> plugins;
for (const auto& entry : fs::directory_iterator(pluginDir)) {
if (entry.is_regular_file()) {
std::string ext = entry.path().extension().string();
#if defined(_WIN32)
if (ext == ".dll") plugins.push_back(entry.path());
#else
if (ext == ".so") plugins.push_back(entry.path());
#endif
}
}
return plugins;
}
Scenario 3: Uploaded File Permissions Too Open
Problem: Uploaded files have chmod 777-like permissions, creating security risk.
Solution: Use std::filesystem::permissions() to restrict permissions after file creation.
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
#include <filesystem>
namespace fs = std::filesystem;
void restrictUploadedFile(const fs::path& file) {
// Owner read/write only
fs::permissions(file, fs::perms::owner_read | fs::perms::owner_write);
}
Scenario 4: Temp Files Not Cleaned, Disk Full
Problem: Crashes or exceptions leave temp files undeleted, accumulating. Solution: Wrap temp files in RAII to auto-delete on scope exit. 다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
class TempFile {
fs::path path_;
public:
TempFile(const fs::path& base = fs::temp_directory_path()) {
path_ = base / ("tmp_" + std::to_string(std::rand()) + ".tmp");
std::ofstream(path_) << "";
}
~TempFile() {
if (fs::exists(path_)) fs::remove(path_);
}
const fs::path& path() const { return path_; }
};
2. std::filesystem Overview
Architecture
다음은 mermaid를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
flowchart TB
subgraph path["path: Path Representation"]
P1[String/path combination]
P2[operator/]
P3[extension, stem, filename]
P1 --> P2 --> P3
end
subgraph ops[File/Directory Operations]
O1[exists, is_regular_file]
O2[create_directories, remove]
O3[copy, rename]
O1 --> O2 --> O3
end
subgraph iter[Iteration]
I1[directory_iterator]
I2[recursive_directory_iterator]
I1 --> I2
end
path --> ops
path --> iter
Diagram explanation: path represents and combines paths. exists, create_directories, copy manipulate files/directories. directory_iterator traverses one level, recursive_directory_iterator traverses subdirectories.
Compile Options
아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
# Requires C++17
g++ -std=c++17 -o fs_demo fs_demo.cpp
# Windows (MSVC)
# /std:c++17
Header and Namespace
Include <filesystem> and conventionally abbreviate with namespace fs = std::filesystem;.
3. Path Operations
Path Creation and Combination
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
// 1) Create from string
fs::path p1("/home/user/config");
fs::path p2("settings.json");
// 2) Combine with operator/ (OS separator auto-applied)
fs::path full = p1 / p2;
std::cout << full << "\n"; // Linux: /home/user/config/settings.json
// Windows: /home/user/config\settings.json
// 3) Current directory
fs::path cwd = fs::current_path();
std::cout << "CWD: " << cwd << "\n";
// 4) Executable path (pre-C++23 needs platform-specific API)
// Linux: /proc/self/exe, Windows: GetModuleFileName
}
Code explanation: path creates like string, operator/ combines with OS-appropriate separator. current_path() returns process working directory.
Path Component Extraction
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path p = "/home/user/projects/app/src/main.cpp";
std::cout << "filename: " << p.filename() << "\n"; // main.cpp
std::cout << "stem: " << p.stem() << "\n"; // main
std::cout << "extension: " << p.extension() << "\n"; // .cpp
std::cout << "parent: " << p.parent_path() << "\n"; // .../src
std::cout << "root_name: " << p.root_name() << "\n"; // (Linux: "")
std::cout << "root_path: " << p.root_path() << "\n"; // /
// Convert to relative path
fs::path base = "/home/user/projects";
fs::path rel = fs::relative(p, base);
std::cout << "relative: " << rel << "\n"; // app/src/main.cpp
}
Code explanation: filename() is last component, stem() excludes extension, extension() is .cpp, parent_path() is parent directory. relative(p, base) creates relative path from base.
Path Normalization and Absolute Path
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path p = "config/../config/settings.json";
// Normalize: remove . and ..
fs::path canonical = fs::weakly_canonical(p);
std::cout << "weakly_canonical: " << canonical << "\n";
// Absolute path (path must exist)
if (fs::exists(p)) {
fs::path abs = fs::absolute(p);
std::cout << "absolute: " << abs << "\n";
fs::path can = fs::canonical(p); // Resolves symlinks, must exist
std::cout << "canonical: " << can << "\n";
}
// Path comparison
fs::path a = "/a/b/c";
fs::path b = "/a/b/c";
std::cout << "equal: " << (a == b) << "\n";
}
Code explanation: weakly_canonical normalizes ./.. and works even if path doesn’t exist. canonical requires path to exist and resolves symlinks. absolute creates absolute path from current directory.
Complete Path Manipulation Example
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// Copy-paste and run: g++ -std=c++17 -o path_demo path_demo.cpp && ./path_demo
#include <filesystem>
#include <iostream>
#include <string>
namespace fs = std::filesystem;
int main() {
fs::path base = fs::current_path();
fs::path configDir = base / "config";
fs::path settingsPath = configDir / "app" / "settings.json";
std::cout << "Base: " << base << "\n";
std::cout << "Config dir: " << configDir << "\n";
std::cout << "Settings: " << settingsPath << "\n";
std::cout << "Filename: " << settingsPath.filename() << "\n";
std::cout << "Stem: " << settingsPath.stem() << "\n";
std::cout << "Ext: " << settingsPath.extension() << "\n";
// Convert to string
std::string strPath = settingsPath.string(); // OS native format
std::string u8Path = settingsPath.u8string(); // UTF-8 (C++20)
}
4. Directory Iteration
directory_iterator: One Level Only
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path dir = ".";
for (const auto& entry : fs::directory_iterator(dir)) {
std::cout << entry.path().filename() << " - ";
if (entry.is_regular_file()) {
std::cout << "file, " << fs::file_size(entry) << " bytes\n";
} else if (entry.is_directory()) {
std::cout << "dir\n";
} else if (entry.is_symlink()) {
std::cout << "symlink -> " << fs::read_symlink(entry) << "\n";
}
}
}
Code explanation: directory_iterator traverses only direct children of specified directory. entry.path() gets path, entry.is_regular_file() checks type.
recursive_directory_iterator: Including Subdirectories
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
#include <string>
namespace fs = std::filesystem;
void listAll(const fs::path& dir) {
for (const auto& entry : fs::recursive_directory_iterator(dir,
fs::directory_options::skip_permission_denied)) {
// depth(): current depth (0 = top level)
std::string indent(entry.depth() * 2, ' ');
std::cout << indent << entry.path().filename() << "\n";
}
}
Code explanation: recursive_directory_iterator recursively traverses subdirectories. entry.depth() provides indentation depth, skip_permission_denied skips directories without permission.
Filter by Extension
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <string>
#include <vector>
namespace fs = std::filesystem;
std::vector<fs::path> findFilesByExtension(const fs::path& dir,
const std::string& ext) {
std::vector<fs::path> result;
for (const auto& entry : fs::recursive_directory_iterator(dir,
fs::directory_options::skip_permission_denied)) {
if (entry.is_regular_file() && entry.path().extension() == ext) {
result.push_back(entry.path());
}
}
return result;
}
int main() {
auto cppFiles = findFilesByExtension(".", ".cpp");
for (const auto& p : cppFiles) {
std::cout << p << "\n";
}
}
Directory Iteration Error Handling
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
#include <system_error>
namespace fs = std::filesystem;
bool safeListDir(const fs::path& dir) {
std::error_code ec;
auto iter = fs::directory_iterator(dir, ec);
if (ec) {
std::cerr << "Cannot open " << dir << ": " << ec.message() << "\n";
return false;
}
for (const auto& entry : fs::directory_iterator(dir, ec)) {
if (ec) {
std::cerr << "Iterator error: " << ec.message() << "\n";
return false;
}
std::cout << entry.path().filename() << "\n";
}
return true;
}
Code explanation: Passing std::error_code to directory_iterator constructor and increment handles failures with error codes instead of exceptions.
5. File Operations
File Existence and Type Check
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void checkPath(const fs::path& p) {
if (!fs::exists(p)) {
std::cout << "Does not exist\n";
return;
}
if (fs::is_regular_file(p)) {
std::cout << "Regular file, size: " << fs::file_size(p) << "\n";
} else if (fs::is_directory(p)) {
std::cout << "Directory\n";
} else if (fs::is_symlink(p)) {
std::cout << "Symlink -> " << fs::read_symlink(p) << "\n";
} else if (fs::is_block_file(p)) {
std::cout << "Block device\n";
} else if (fs::is_character_file(p)) {
std::cout << "Character device\n";
} else if (fs::is_fifo(p)) {
std::cout << "FIFO\n";
} else if (fs::is_socket(p)) {
std::cout << "Socket\n";
}
}
Code explanation: exists() checks existence, is_regular_file() etc. distinguish types. file_size() only works for regular files.
Directory Creation
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path dir = "a/b/c/d";
// create_directories: creates all intermediate paths
bool created = fs::create_directories(dir);
std::cout << "Created: " << created << "\n";
// create_directory: one level only (parent must exist)
fs::create_directory("single_dir");
// Returns false if already exists, true if created
if (fs::create_directories("logs/2026/03")) {
std::cout << "Log dir created\n";
}
}
Code explanation: create_directories creates all intermediate paths like mkdir -p, create_directory creates one level only.
File Copy
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path src = "source.txt";
fs::path dst = "backup/copy.txt";
// Options: overwrite_existing, recursive (for directories), copy_symlinks
fs::copy_options opts = fs::copy_options::overwrite_existing;
fs::copy_file(src, dst, opts); // Copy file only
// Copy entire directory
fs::copy("src_dir", "dst_dir",
fs::copy_options::recursive | fs::copy_options::overwrite_existing);
}
Code explanation: copy_file copies single file, copy can copy directories with recursive. Without overwrite_existing, error occurs if destination exists.
File Move/Rename
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path oldName = "temp.txt";
fs::path newName = "final.txt";
fs::rename(oldName, newName); // Same filesystem: atomic move
// Different filesystem: copy then delete
fs::path otherFs = "/mnt/other/disk/file.txt";
fs::rename(oldName, otherFs); // May use copy+remove
}
Code explanation: rename is atomic within same filesystem. Moving across filesystems may use copy+delete.
File Deletion
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path file = "junk.txt";
fs::path dir = "empty_dir";
// Delete file
if (fs::remove(file)) {
std::cout << "Removed " << file << "\n";
}
// Delete empty directory
fs::remove(dir);
// Delete directory tree (including contents)
fs::path tree = "to_delete";
std::uintmax_t n = fs::remove_all(tree);
std::cout << "Removed " << n << " items\n";
}
Code explanation: remove deletes file or empty directory, remove_all deletes including subdirectories and returns count of deleted items.
Symbolic Links
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path target = "real_file.txt";
fs::path link = "symlink_to_file";
fs::create_symlink(target, link); // Relative path link
// fs::create_directory_symlink(target, "symlink_to_dir"); // For directories
if (fs::is_symlink(link)) {
fs::path resolved = fs::read_symlink(link);
std::cout << "Link points to: " << resolved << "\n";
// Actual file path (absolute)
fs::path canonical = fs::canonical(link);
std::cout << "Canonical: " << canonical << "\n";
}
}
Code explanation: create_symlink creates symbolic link, read_symlink reads target path. canonical follows links to final path.
Complete File Copy Utility
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// Copy-paste and run: g++ -std=c++17 -o fs_copy fs_copy.cpp && ./fs_copy src dst
#include <filesystem>
#include <iostream>
#include <system_error>
namespace fs = std::filesystem;
bool copyRecursive(const fs::path& src, const fs::path& dst) {
std::error_code ec;
if (!fs::exists(src, ec)) {
std::cerr << "Source does not exist: " << src << "\n";
return false;
}
if (fs::is_regular_file(src)) {
fs::create_directories(dst.parent_path(), ec);
if (ec) {
std::cerr << "Cannot create parent: " << ec.message() << "\n";
return false;
}
fs::copy_file(src, dst, fs::copy_options::overwrite_existing, ec);
if (ec) {
std::cerr << "Copy failed: " << ec.message() << "\n";
return false;
}
return true;
}
if (fs::is_directory(src)) {
fs::create_directories(dst, ec);
for (const auto& entry : fs::directory_iterator(src)) {
fs::path newDst = dst / entry.path().filename();
if (!copyRecursive(entry.path(), newDst)) {
return false;
}
}
return true;
}
std::cerr << "Unsupported type: " << src << "\n";
return false;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <source> <destination>\n";
return 1;
}
return copyRecursive(argv[1], argv[2]) ? 0 : 1;
}
6. Permissions
Check Permissions
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void showPermissions(const fs::path& p) {
if (!fs::exists(p)) return;
auto perms = fs::status(p).permissions();
auto has = [perms](fs::perms p) { return (perms & p) != fs::perms::none; };
std::cout << "Owner read: " << has(fs::perms::owner_read) << "\n";
std::cout << "Owner write: " << has(fs::perms::owner_write) << "\n";
std::cout << "Owner exec: " << has(fs::perms::owner_exec) << "\n";
std::cout << "Group read: " << has(fs::perms::group_read) << "\n";
std::cout << "Others read: " << has(fs::perms::others_read) << "\n";
}
Code explanation: fs::status(p).permissions() gets permission bits, AND with owner_read etc. to check.
Set Permissions
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path file = "secret.txt";
// Owner read/write only (600)
fs::permissions(file,
fs::perms::owner_read | fs::perms::owner_write,
fs::perm_options::replace);
// Add execute permission (keep existing)
fs::permissions(file,
fs::perms::owner_exec,
fs::perm_options::add);
// Remove permissions
fs::permissions(file,
fs::perms::others_read | fs::perms::others_write,
fs::perm_options::remove);
}
Code explanation: replace replaces with specified permissions, add adds, remove removes. owner_read | owner_write corresponds to chmod 600.
Create File with Permissions
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
void createRestrictedFile(const fs::path& path, const std::string& content) {
std::ofstream out(path);
if (!out) return;
out << content;
out.close();
// Restrict permissions immediately after creation (owner read/write only)
fs::permissions(path,
fs::perms::owner_read | fs::perms::owner_write,
fs::perm_options::replace);
}
Code explanation: After writing file, restrict permissions with permissions—applicable for uploads, config files, etc.
7. Common Errors and Solutions
Error 1: filesystem_error Exception Terminates Program
Symptom: fs::copy_file or fs::remove throws filesystem_error.
Cause: By default, std::filesystem functions throw exceptions on failure. Missing files or insufficient permissions cause exceptions.
Solution:
아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ❌ Throws exception
fs::remove("nonexistent.txt"); // throws filesystem_error
// ✅ Use error_code
std::error_code ec;
fs::remove("nonexistent.txt", ec);
if (ec) {
std::cerr << "Remove failed: " << ec.message() << "\n";
}
Error 2: file_size Called on Directory
Symptom: fs::file_size(dir) throws exception or returns wrong result.
Cause: file_size only works for regular files.
Solution:
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ❌ Wrong usage
auto size = fs::file_size(somePath); // Error if directory
// ✅ Check type first
if (fs::is_regular_file(path)) {
auto size = fs::file_size(path);
}
Error 3: recursive_directory_iterator Stops on Permission Denied
Symptom: Traversing / or system directories throws exception.
Cause: Accessing directories without permission throws by default.
Solution:
아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ✅ skip_permission_denied option
for (const auto& entry : fs::recursive_directory_iterator("/",
fs::directory_options::skip_permission_denied)) {
// Skips directories without permission
}
Error 4: Garbled Paths on Windows
Symptom: path << u8"한글" output is garbled.
Cause: Windows console default encoding may not be UTF-8.
Solution:
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
// Windows: set console to UTF-8
#ifdef _WIN32
#include <windows.h>
SetConsoleOutputCP(65001);
#endif
// Or use u8string() for UTF-8 string
std::string u8 = path.u8string();
Error 5: copy_file Doesn’t Overwrite Existing File
Symptom: Copy fails when destination file exists. Cause: Default behavior doesn’t overwrite existing files. Solution:
// ✅ overwrite_existing option
fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
Error 6: create_directories Fails
Symptom: create_directories("a/b/c") returns false.
Cause: If a already exists as regular file, can’t create directory under it. Or insufficient permissions.
Solution:
아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
std::error_code ec;
bool ok = fs::create_directories(path, ec);
if (!ok && ec) {
std::cerr << "Create failed: " << ec.message()
<< " (path: " << path << ")\n";
}
// Check if a is a file
if (fs::exists("a") && fs::is_regular_file("a")) {
std::cerr << "Cannot create: 'a' is a file\n";
}
8. Best Practices
1. Use error_code to Disable Exceptions
In production, handling file system errors with std::error_code instead of exceptions is more stable.
아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
std::error_code ec;
if (!fs::exists(path, ec) || ec) {
logError("Path check failed", ec);
return false;
}
2. Always Combine Paths with path
Use path and operator/ instead of string concatenation.
아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ❌
std::string p = base + "/" + sub + "/" + file;
// ✅
fs::path p = fs::path(base) / sub / file;
3. Double-Check with exists + is_regular_file
Verify type before file operations.
if (fs::exists(p) && fs::is_regular_file(p)) {
auto size = fs::file_size(p);
}
4. Beware of TOCTOU
Between exists check and actual use, file may be deleted or changed. Ultimately verify actual operation result like ifstream::is_open().
다음은 간단한 cpp 코드 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
if (fs::exists(p)) {
std::ifstream f(p);
if (!f) { /* Open failed - may have been deleted after exists */ }
}
5. Use skip_permission_denied for Recursive Traversal
When scanning entire system, use skip_permission_denied.
9. Production Patterns
Pattern 1: Safe Directory Creation
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <system_error>
namespace fs = std::filesystem;
bool ensureDirectory(const fs::path& dir) {
std::error_code ec;
if (fs::exists(dir, ec)) {
if (ec) return false;
return fs::is_directory(dir, ec);
}
return fs::create_directories(dir, ec) && !ec;
}
Pattern 2: Atomic File Write (temp + rename)
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <fstream>
#include <system_error>
namespace fs = std::filesystem;
bool atomicWrite(const fs::path& target, const std::string& content) {
std::error_code ec;
fs::path tmp = target.parent_path() / (target.filename().string() + ".tmp");
std::ofstream out(tmp, std::ios::binary);
if (!out) return false;
out << content;
out.close();
if (!out) {
fs::remove(tmp, ec);
return false;
}
fs::rename(tmp, target, ec);
if (ec) {
fs::remove(tmp, ec);
return false;
}
return true;
}
Explanation: Write to temp file first, then atomically rename to target. If write fails, target remains unchanged.
Pattern 3: Calculate Directory Size
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <cstdint>
namespace fs = std::filesystem;
std::uintmax_t directorySize(const fs::path& dir) {
std::uintmax_t total = 0;
std::error_code ec;
for (const auto& entry : fs::recursive_directory_iterator(dir,
fs::directory_options::skip_permission_denied, ec)) {
if (ec) return 0;
if (entry.is_regular_file(ec) && !ec) {
total += fs::file_size(entry, ec);
}
}
return total;
}
Pattern 4: Temp Directory RAII
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <random>
#include <sstream>
namespace fs = std::filesystem;
class TempDirectory {
fs::path path_;
public:
TempDirectory() {
std::ostringstream oss;
oss << fs::temp_directory_path() / "tmp_" << std::rand();
path_ = oss.str();
fs::create_directories(path_);
}
~TempDirectory() {
std::error_code ec;
fs::remove_all(path_, ec);
}
const fs::path& path() const { return path_; }
};
Pattern 5: Config File Path Resolution
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
fs::path resolveConfigPath(const std::string& filename) {
// 1) Environment variable
const char* configHome = std::getenv("XDG_CONFIG_HOME");
if (configHome) {
fs::path p = fs::path(configHome) / "myapp" / filename;
if (fs::exists(p)) return fs::canonical(p);
}
// 2) Home directory
const char* home = std::getenv("HOME");
if (home) {
fs::path p = fs::path(home) / ".config" / "myapp" / filename;
if (fs::exists(p)) return fs::canonical(p);
}
// 3) Current directory
if (fs::exists(filename)) return fs::canonical(filename);
return {};
}
10. Checklist
Items to verify during implementation:
- Compile with
-std=c++17or higher - Use
pathandoperator/for path combination - Use
std::error_codeoverloads in production - Check
is_regular_filebeforefile_size - Apply
skip_permission_deniedtorecursive_directory_iterator - Check if
overwrite_existingneeded forcopy_file - Consider atomic write (temp + rename) for critical data
- Clean up temp files/directories with RAII
11. Summary
| Item | Content |
|---|---|
| path | Path representation, combine with operator/ |
| exists | Check existence |
| is_regular_file | Check if regular file |
| create_directories | Create including intermediate paths |
| directory_iterator | Traverse one level |
| recursive_directory_iterator | Traverse including subdirectories |
| copy_file / copy | Copy file/directory |
| remove / remove_all | Delete |
| permissions | Check/set permissions |
| Core Principles: |
- Handle cross-platform paths with
path - Handle errors without exceptions using
error_code - Verify type before file operations
- Maintain data integrity with atomic writes
Related Articles
- C++ File I/O | ifstream, ofstream, and Handling “File Open Failed” Errors
- C++ Early Look at C++23 Core Features [#37-1]
- C++ Exception Handling | try-catch-throw & Exceptions vs Error Codes
Keywords
C++ filesystem, std::filesystem, path operations, directory traversal, file copy, file permissions, cross-platform, C++17
One-line summary: Use std::filesystem::path to combine paths and handle file systems safely with create_directories, copy_file, directory_iterator. Next, read File I/O Basics (#11-1).
Previous: C++23 Core Features (#37-1)
Next: C++ Practical Guide #38-1: Clean Code Basics