C++ Filesystem 빠른 참조 | "파일시스템" C++17 라이브러리 가이드

C++ Filesystem 빠른 참조 | "파일시스템" C++17 라이브러리 가이드

이 글의 핵심

C++ Filesystem에 대해 정리한 개발 블로그 글입니다. #include <filesystem> #include <iostream> namespace fs = std::filesystem;

기본 사용법

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

int main() {
    fs::path p = "/home/user/file.txt";
    
    cout << "경로: " << p << endl;
    cout << "파일명: " << p.filename() << endl;
    cout << "확장자: " << p.extension() << endl;
    cout << "디렉토리: " << p.parent_path() << endl;
}

경로 조작

fs::path p1 = "/home/user";
fs::path p2 = "documents";
fs::path p3 = "file.txt";

// 경로 결합
fs::path full = p1 / p2 / p3;
cout << full << endl;  // /home/user/documents/file.txt

// 확장자 변경
fs::path file = "test.txt";
file.replace_extension(".md");
cout << file << endl;  // test.md

// 절대 경로
fs::path rel = "file.txt";
fs::path abs = fs::absolute(rel);
cout << abs << endl;

파일 존재 확인

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

if (fs::exists(p)) {
    cout << "파일 존재" << endl;
}

if (fs::is_regular_file(p)) {
    cout << "일반 파일" << endl;
}

if (fs::is_directory(p)) {
    cout << "디렉토리" << endl;
}

실전 예시

예시 1: 디렉토리 순회

#include <filesystem>
namespace fs = std::filesystem;

void listFiles(const fs::path& dir) {
    for (const auto& entry : fs::directory_iterator(dir)) {
        cout << entry.path() << endl;
        
        if (entry.is_regular_file()) {
            cout << "  파일, 크기: " << entry.file_size() << " bytes" << endl;
        } else if (entry.is_directory()) {
            cout << "  디렉토리" << endl;
        }
    }
}

int main() {
    listFiles(".");
}

예시 2: 재귀 순회

void listFilesRecursive(const fs::path& dir) {
    for (const auto& entry : fs::recursive_directory_iterator(dir)) {
        // 들여쓰기
        int depth = distance(dir.begin(), entry.path().begin());
        cout << string(depth * 2, ' ') << entry.path().filename() << endl;
    }
}

int main() {
    listFilesRecursive(".");
}

예시 3: 파일 검색

#include <vector>

vector<fs::path> findFiles(const fs::path& dir, const string& extension) {
    vector<fs::path> result;
    
    for (const auto& entry : fs::recursive_directory_iterator(dir)) {
        if (entry.is_regular_file() && entry.path().extension() == extension) {
            result.push_back(entry.path());
        }
    }
    
    return result;
}

int main() {
    auto cppFiles = findFiles(".", ".cpp");
    
    cout << "C++ 파일 " << cppFiles.size() << "개:" << endl;
    for (const auto& file : cppFiles) {
        cout << "  " << file << endl;
    }
}

예시 4: 디렉토리 생성

void createDirectoryStructure() {
    fs::path base = "project";
    
    // 디렉토리 생성
    fs::create_directory(base);
    fs::create_directory(base / "src");
    fs::create_directory(base / "include");
    fs::create_directory(base / "build");
    
    // 중첩 디렉토리 생성
    fs::create_directories(base / "src" / "utils" / "helpers");
    
    cout << "디렉토리 구조 생성 완료" << endl;
}

int main() {
    createDirectoryStructure();
}

파일 작업

// 파일 복사
fs::copy("source.txt", "dest.txt");

// 파일 이동
fs::rename("old.txt", "new.txt");

// 파일 삭제
fs::remove("file.txt");

// 디렉토리 삭제 (재귀)
fs::remove_all("directory");

// 파일 크기
uintmax_t size = fs::file_size("file.txt");

// 수정 시간
auto time = fs::last_write_time("file.txt");

경로 정규화

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

// 정규화
fs::path canonical = fs::canonical(p);
cout << canonical << endl;  // /home/user/file.txt

// 상대 경로
fs::path rel = fs::relative("/home/user/file.txt", "/home");
cout << rel << endl;  // user/file.txt

자주 발생하는 문제

문제 1: 예외 처리

// ❌ 예외 무시
fs::remove("file.txt");  // 파일 없으면 예외

// ✅ 예외 처리
try {
    fs::remove("file.txt");
} catch (const fs::filesystem_error& e) {
    cout << "에러: " << e.what() << endl;
}

// ✅ 에러 코드 사용
error_code ec;
fs::remove("file.txt", ec);
if (ec) {
    cout << "에러: " << ec.message() << endl;
}

문제 2: 심볼릭 링크

fs::path link = "symlink";

// ❌ 심볼릭 링크 따라감
if (fs::is_regular_file(link)) {
    // 링크 대상 체크
}

// ✅ 심볼릭 링크 자체 체크
if (fs::is_symlink(link)) {
    cout << "심볼릭 링크" << endl;
}

문제 3: 권한 문제

// ❌ 권한 없는 디렉토리
for (const auto& entry : fs::directory_iterator("/root")) {
    // 예외 발생
}

// ✅ 예외 처리
try {
    for (const auto& entry : fs::directory_iterator("/root")) {
        cout << entry.path() << endl;
    }
} catch (const fs::filesystem_error& e) {
    cout << "접근 거부" << endl;
}

파일 정보

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

// 권한
auto perms = fs::status(p).permissions();

// 크기
uintmax_t size = fs::file_size(p);

// 수정 시간
auto mtime = fs::last_write_time(p);

// 공간 정보
fs::space_info space = fs::space(".");
cout << "전체: " << space.capacity << endl;
cout << "사용 가능: " << space.available << endl;

FAQ

Q1: filesystem은 언제 사용하나요?

A:

  • 파일/디렉토리 작업
  • 경로 조작
  • 파일 검색
  • 빌드 도구

Q2: 기존 방식과 차이는?

A:

  • 크로스 플랫폼
  • 타입 안전
  • 예외 안전
  • 더 편리한 API

Q3: 성능은?

A: 기존 시스템 콜과 비슷하거나 약간 느립니다.

Q4: 에러 처리는?

A:

  • 예외 버전 (기본)
  • error_code 버전 (예외 없음)

Q5: 경로 구분자는?

A: 자동으로 플랫폼에 맞게 변환됩니다 (/ 또는 \).

Q6: Filesystem 학습 리소스는?

A:

  • cppreference.com
  • “C++17: The Complete Guide”
  • Boost.Filesystem 문서

같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

  • C++ Filesystem | “파일시스템 라이브러리” 가이드
  • C++ File Status | “파일 상태” 가이드
  • C++ File Operations | “파일 연산” 가이드

관련 글

  • C++ std::filesystem 완벽 가이드 | 경로·디렉토리·파일·권한 한 번에 정리
  • C++ Directory Iterator |
  • C++ File Operations |
  • C++ File Status |
  • C++ Filesystem 개념 정리 |