C++ path | "경로 처리" 가이드

C++ path | "경로 처리" 가이드

이 글의 핵심

C++ path에 대한 실전 가이드입니다.

들어가며

std::filesystem::path는 C++17의 플랫폼 독립적 경로 처리 클래스입니다.


1. path란?

기본 사용

#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;
}

특징:

  • 플랫폼 독립적
  • 자동 구분자 변환 (/, \)
  • 다양한 메서드 제공

2. 경로 조작

경로 분해

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main() {
    fs::path p = "/home/user/documents/report.pdf";
    
    std::cout << "전체: " << p << std::endl;
    std::cout << "파일명: " << p.filename() << std::endl;      // "report.pdf"
    std::cout << "확장자: " << p.extension() << std::endl;     // ".pdf"
    std::cout << "기본명: " << p.stem() << std::endl;          // "report"
    std::cout << "부모: " << p.parent_path() << std::endl;     // "/home/user/documents"
    std::cout << "루트: " << p.root_path() << std::endl;       // "/"
    
    return 0;
}

경로 결합

fs::path dir = "/home/user";
fs::path file = "file.txt";

// / 연산자
fs::path full = dir / file;  // "/home/user/file.txt"

// /= 연산자
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. 경로 변환

절대 경로

fs::path p = "file.txt";

// 절대 경로로 변환
fs::path abs = fs::absolute(p);
std::cout << abs << std::endl;  // "/current/directory/file.txt"

정규 경로

fs::path p = "/home/user/../user/./file.txt";

// 정규 경로 (파일 존재 필요)
fs::path canonical = fs::canonical(p);
std::cout << canonical << std::endl;  // "/home/user/file.txt"

// weakly_canonical (파일 존재 불필요)
fs::path p2 = "/home/user/nonexistent.txt";
fs::path weak = fs::weakly_canonical(p2);
std::cout << weak << std::endl;

상대 경로

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. 경로 확인

경로 타입

fs::path p = "/home/user/file.txt";

// 절대 경로?
if (p.is_absolute()) {
    std::cout << "절대 경로" << std::endl;
}

// 상대 경로?
if (p.is_relative()) {
    std::cout << "상대 경로" << std::endl;
}

// 비어있음?
if (p.empty()) {
    std::cout << "빈 경로" << std::endl;
}

// 경로 존재?
if (fs::exists(p)) {
    std::cout << "존재함" << std::endl;
}

5. 확장자 처리

확장자 변경

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"

확장자 확인

fs::path p = "image.png";

if (p.extension() == ".png") {
    std::cout << "PNG 파일" << 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 << "이미지 파일" << std::endl;
}

6. 경로 비교

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 << "같음" << std::endl;
}

if (p1 != p3) {
    std::cout << "다름" << std::endl;
}

// 대소문자 구분 (플랫폼 의존)
// Windows: 구분 안 함
// Linux: 구분함

7. 실전 예제

예제 1: 파일 확장자 일괄 변경

#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 << "변경: " << entry.path().filename() 
                      << " → " << new_path.filename() << std::endl;
        }
    }
}

int main() {
    rename_extensions("./images", ".jpeg", ".jpg");
    return 0;
}

예제 2: 백업 경로 생성

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 << std::endl;
    std::cout << "백업: " << backup << std::endl;
    // 백업: /home/user/document_backup.txt
    
    return 0;
}

정리

핵심 요약

  1. path: C++17 플랫폼 독립 경로
  2. / 연산자: 경로 결합
  3. filename(): 파일명 추출
  4. extension(): 확장자 추출
  5. absolute(): 절대 경로 변환
  6. canonical(): 정규 경로 (존재 필요)

주요 메서드

메서드설명
filename()파일명
extension()확장자
stem()확장자 제외 파일명
parent_path()부모 경로
root_path()루트 경로
replace_extension()확장자 변경

다음 단계

  • C++ Filesystem
  • C++ Directory Iterator
  • C++ File Operations

관련 글

  • C++ Directory Iterator |
  • C++ File Operations |
  • C++ File Status |
  • C++ Filesystem 빠른 참조 |
  • C++ Filesystem 개념 정리 |