[2026] C++ std::filesystem Complete Guide | Cross-Platform Path, Directory, File Operations [#37-1]

[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

  1. Problem Scenarios
  2. std::filesystem Overview
  3. Path Operations
  4. Directory Iteration
  5. File Operations
  6. Permissions
  7. Common Errors and Solutions
  8. Best Practices
  9. Production Patterns
  10. Checklist
  11. 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.

다음은 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++17 or higher
  • Use path and operator/ for path combination
  • Use std::error_code overloads in production
  • Check is_regular_file before file_size
  • Apply skip_permission_denied to recursive_directory_iterator
  • Check if overwrite_existing needed for copy_file
  • Consider atomic write (temp + rename) for critical data
  • Clean up temp files/directories with RAII

11. Summary

ItemContent
pathPath representation, combine with operator/
existsCheck existence
is_regular_fileCheck if regular file
create_directoriesCreate including intermediate paths
directory_iteratorTraverse one level
recursive_directory_iteratorTraverse including subdirectories
copy_file / copyCopy file/directory
remove / remove_allDelete
permissionsCheck/set permissions
Core Principles:
  1. Handle cross-platform paths with path
  2. Handle errors without exceptions using error_code
  3. Verify type before file operations
  4. Maintain data integrity with atomic writes

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

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3