본문으로 건너뛰기 C++ std::filesystem::path | Cross-platform paths in C++17

C++ std::filesystem::path | Cross-platform paths in C++17

C++ std::filesystem::path | Cross-platform paths in C++17

이 글의 핵심

Use std::filesystem::path to join, normalize, and inspect paths portably. Covers filename, extension, parent_path, absolute, canonical, weakly_canonical, and practical rename and backup patterns.

Introduction

std::filesystem::path is the C++17 class for portable path handling.

1. What is path?

Basic usage

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
    fs::path p = "/home/user/file.txt";
    fs::path p2 = "C:\\Users\\user\\file.txt";  // Windows
    
    std::cout << p << std::endl;
    std::cout << p2 << std::endl;
    
    return 0;
}

Features:

  • Platform-independent
  • Automatic separator handling (/, \\)
  • Rich API for decomposition and manipulation

2. Path manipulation

Decomposition

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
    fs::path p = "/home/user/documents/report.pdf";
    
    std::cout << "Full: " << p << std::endl;
    std::cout << "Filename: " << p.filename() << std::endl;      // "report.pdf"
    std::cout << "Extension: " << p.extension() << std::endl;     // ".pdf"
    std::cout << "Stem: " << p.stem() << std::endl;             // "report"
    std::cout << "Parent: " << p.parent_path() << std::endl;    // "/home/user/documents"
    std::cout << "Root: " << p.root_path() << std::endl;          // "/"
    
    return 0;
}

Joining paths

fs::path dir = "/home/user";
fs::path file = "file.txt";
// / operator
fs::path full = dir / file;  // "/home/user/file.txt"
// /= operator
fs::path p = "/home/user";
p /= "documents";
p /= "file.txt";
std::cout << p << std::endl;  // "/home/user/documents/file.txt"
// append
fs::path p2 = "/home";
p2.append("user").append("file.txt");

3. Path normalization

Absolute paths

fs::path p = "file.txt";
fs::path abs = fs::absolute(p);
std::cout << abs << std::endl;  // e.g. "/current/directory/file.txt"

Canonical paths

fs::path p = "/home/user/../user/./file.txt";
// Canonical (target must exist)
fs::path canonical = fs::canonical(p);
std::cout << canonical << std::endl;  // "/home/user/file.txt"
// weakly_canonical (need not exist)
fs::path p2 = "/home/user/nonexistent.txt";
fs::path weak = fs::weakly_canonical(p2);
std::cout << weak << std::endl;

Relative paths

fs::path abs = "/home/user/documents/file.txt";
fs::path base = "/home/user";
fs::path rel = fs::relative(abs, base);
std::cout << rel << std::endl;  // "documents/file.txt"

4. Path properties

fs::path p = "/home/user/file.txt";
if (p.is_absolute()) {
    std::cout << "Absolute path" << std::endl;
}
if (p.is_relative()) {
    std::cout << "Relative path" << std::endl;
}
if (p.empty()) {
    std::cout << "Empty path" << std::endl;
}
if (fs::exists(p)) {
    std::cout << "Exists" << std::endl;
}

5. Extensions

Changing extensions

fs::path p = "document.txt";
p.replace_extension(".pdf");
std::cout << p << std::endl;  // "document.pdf"
p.replace_extension();
std::cout << p << std::endl;  // "document"
p.replace_extension(".docx");
std::cout << p << std::endl;  // "document.docx"

Checking extensions

#include <vector>
#include <algorithm>
fs::path p = "image.png";
if (p.extension() == ".png") {
    std::cout << "PNG file" << std::endl;
}
std::vector<std::string> image_exts = {".png", ".jpg", ".jpeg", ".gif"};
if (std::find(image_exts.begin(), image_exts.end(), p.extension()) != image_exts.end()) {
    std::cout << "Image file" << std::endl;
}

6. Comparing paths

fs::path p1 = "/home/user/file.txt";
fs::path p2 = "/home/user/file.txt";
fs::path p3 = "/home/user/other.txt";
if (p1 == p2) {
    std::cout << "Equal" << std::endl;
}
if (p1 != p3) {
    std::cout << "Different" << std::endl;
}
// Case sensitivity is platform-dependent
// Windows: often case-insensitive
// Linux: case-sensitive

7. Practical examples

Example 1: Batch extension rename

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void rename_extensions(const fs::path& dir, 
                       const std::string& old_ext, 
                       const std::string& new_ext) {
    for (const auto& entry : fs::directory_iterator(dir)) {
        if (entry.is_regular_file() && entry.path().extension() == old_ext) {
            fs::path new_path = entry.path();
            new_path.replace_extension(new_ext);
            fs::rename(entry.path(), new_path);
            std::cout << "Renamed: " << entry.path().filename() 
                      << " -> " << new_path.filename() << std::endl;
        }
    }
}
int main() {
    rename_extensions("./images", ".jpeg", ".jpg");
    return 0;
}

Example 2: Backup path

fs::path create_backup_path(const fs::path& original) {
    fs::path backup = original;
    backup.replace_extension();
    
    std::string backup_name = backup.filename().string() + "_backup";
    backup = backup.parent_path() / backup_name;
    backup.replace_extension(original.extension());
    
    return backup;
}
int main() {
    fs::path original = "/home/user/document.txt";
    fs::path backup = create_backup_path(original);
    
    std::cout << "Original: " << original << std::endl;
    std::cout << "Backup: " << backup << std::endl;
    
    return 0;
}

Summary

Key points

  1. path: portable path type in C++17
  2. / operator: join segments
  3. filename(), extension(), stem(): decomposition
  4. absolute(): resolve against current directory
  5. canonical(): full normalization (path must exist)

Common methods

MethodRole
filename()File name
extension()Extension including dot
stem()File name without extension
parent_path()Parent directory
root_path()Root component
replace_extension()Change extension

Next steps



Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Use std::filesystem::path to join, normalize, and inspect paths portably. Covers filename, extension, parent_path, absol…

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, path, filesystem, C++17, cross-platform.