콘텐츠로 이동

C++17 std::filesystem 완전 가이드

C++17의 std::filesystem(헤더 <filesystem>, 네임스페이스 std::fs)은 파일시스템 경로 조작, 파일/디렉터리 생성·삭제·복사, 파일 정보 조회를 표준화된 API로 제공합니다. Windows, Linux, macOS를 동일한 코드로 처리할 수 있습니다.


#include <filesystem>
namespace fs = std::filesystem;
fs::path p1 = "C:/Users/user/Documents/file.txt";
fs::path p2 = fs::current_path(); // 현재 작업 디렉터리
// 경로 조합
fs::path dir = "src";
fs::path file = "main.cpp";
fs::path full = dir / file; // "src/main.cpp"
// 경로 구성 요소
fs::path p = "/home/user/docs/file.txt";
std::cout << p.root_path() << "\n"; // "/"
std::cout << p.parent_path() << "\n"; // "/home/user/docs"
std::cout << p.filename() << "\n"; // "file.txt"
std::cout << p.stem() << "\n"; // "file"
std::cout << p.extension() << "\n"; // ".txt"
std::cout << p.relative_path() << "\n"; // "home/user/docs/file.txt"
fs::path p = "src/main.cpp";
// 절대 경로 변환
fs::path abs = fs::absolute(p); // /cwd/src/main.cpp
// 정규화 (., .., 심볼릭 링크 해소)
fs::path canonical = fs::canonical(p); // 실제 존재해야 함
// 상대 경로 계산
fs::path base = "/home/user";
fs::path target = "/home/user/docs/file.txt";
fs::path rel = fs::relative(target, base); // "docs/file.txt"

// 디렉터리 생성
fs::create_directory("output"); // 단일 디렉터리
fs::create_directories("a/b/c/d"); // 중간 경로 포함
// 파일 생성 (표준 파일 스트림 사용)
std::ofstream file("output/data.txt");
file << "Hello, filesystem!\n";
// 파일 복사
fs::copy_file("src.txt", "dst.txt");
fs::copy_file("src.txt", "dst.txt",
fs::copy_options::overwrite_existing); // 덮어쓰기
// 디렉터리 재귀 복사
fs::copy("src_dir", "dst_dir",
fs::copy_options::recursive);
fs::rename("old_name.txt", "new_name.txt");
fs::rename("dir/file.txt", "other_dir/file.txt"); // 이동
fs::remove("file.txt"); // 단일 파일
fs::remove_all("directory"); // 디렉터리 재귀 삭제
// 반환값: 삭제된 항목 수
std::uintmax_t count = fs::remove_all("temp");

fs::path p = "example.txt";
// 존재 여부
bool exists = fs::exists(p);
bool isFile = fs::is_regular_file(p);
bool isDir = fs::is_directory(p);
bool isSymlink = fs::is_symlink(p);
// 파일 크기
std::uintmax_t size = fs::file_size(p);
// 최종 수정 시간
auto time = fs::last_write_time(p);
auto sctp = std::chrono::file_clock::to_sys(time); // C++20
// 권한
fs::perms perms = fs::status(p).permissions();
bool readable = (perms & fs::perms::owner_read) != fs::perms::none;

fs::path dir = "src";
for (const fs::directory_entry& entry : fs::directory_iterator(dir)) {
std::cout << entry.path() << "\n";
std::cout << " 타입: " << (entry.is_regular_file() ? "파일" : "디렉터리") << "\n";
if (entry.is_regular_file()) {
std::cout << " 크기: " << entry.file_size() << " bytes\n";
}
}
for (const auto& entry : fs::recursive_directory_iterator("project")) {
if (entry.is_regular_file() && entry.path().extension() == ".cpp") {
std::cout << entry.path() << "\n";
}
}
// directory_iterator 자체는 정렬 미보장
std::vector<fs::path> entries;
for (const auto& e : fs::directory_iterator("src")) {
entries.push_back(e.path());
}
std::sort(entries.begin(), entries.end());
for (const auto& p : entries) {
std::cout << p.filename() << "\n";
}

try {
fs::copy_file("nonexistent.txt", "dst.txt");
} catch (const fs::filesystem_error& e) {
std::cerr << "오류: " << e.what() << "\n";
std::cerr << "경로1: " << e.path1() << "\n";
std::cerr << "경로2: " << e.path2() << "\n";
}
std::error_code ec;
fs::copy_file("nonexistent.txt", "dst.txt", ec);
if (ec) {
std::cerr << "오류: " << ec.message() << "\n";
// 예외 발생 없음
}
// 거의 모든 함수에 ec 오버로드 존재
if (!fs::exists("path", ec) && !ec) {
// 존재하지 않음 (에러 아님)
}

std::vector<fs::path> findFiles(const fs::path& root, const std::string& ext) {
std::vector<fs::path> results;
std::error_code ec;
for (const auto& entry : fs::recursive_directory_iterator(root, ec)) {
if (ec) break;
if (entry.is_regular_file() && entry.path().extension() == ext) {
results.push_back(entry.path());
}
}
std::sort(results.begin(), results.end());
return results;
}
auto cppFiles = findFiles("project/src", ".cpp");
void safeReplace(const fs::path& target, const fs::path& newFile) {
fs::path backup = target;
backup += ".bak";
std::error_code ec;
// 1. 기존 파일 백업
if (fs::exists(target)) {
fs::rename(target, backup, ec);
if (ec) throw std::runtime_error("백업 실패: " + ec.message());
}
// 2. 새 파일 이동
fs::rename(newFile, target, ec);
if (ec) {
// 복원
if (fs::exists(backup)) fs::rename(backup, target);
throw std::runtime_error("교체 실패: " + ec.message());
}
// 3. 백업 삭제
fs::remove(backup, ec);
}
class TempDir {
fs::path path_;
public:
TempDir() : path_(fs::temp_directory_path() / "myapp_XXXXXX") {
fs::create_directories(path_);
}
~TempDir() {
std::error_code ec;
fs::remove_all(path_, ec);
}
const fs::path& path() const { return path_; }
};
{
TempDir tmp;
auto file = tmp.path() / "work.dat";
// 작업 수행
} // 소멸자에서 자동 삭제

  • Windows는 \, Linux/macOS는 /path::operator/로 구성하면 플랫폼 무관
  • 대소문자 구분: Windows는 구분 없음, Linux는 구분 있음
  • path::string()은 플랫폼 기본 문자 형식, path::generic_string()은 항상 / 구분자

작업함수
경로 조합path / other
존재 확인fs::exists()
디렉터리 생성fs::create_directories()
파일 복사fs::copy_file()
재귀 삭제fs::remove_all()
반복 순회recursive_directory_iterator
에러 처리예외 또는 std::error_code