C++17의 std::filesystem
라이브러리는 파일 및 디렉터리 조작을 위한 강력한 기능을 제공합니다. 이 라이브러리는 플랫폼에 독립적인 파일 시스템 접근을 지원하며, 복잡한 경로 변환, 파일 속성 조회, 디렉터리 탐색 등의 작업을 쉽게 수행할 수 있도록 설계되었습니다.
전통적으로 C++에서 파일 조작은 stdio.h
의 C 표준 함수나 <fstream>
을 사용하여 이루어졌지만, 이러한 방법은 플랫폼별 차이를 처리하기 어렵고, 파일 시스템 작업을 직관적으로 표현하기 어려웠습니다. std::filesystem
은 이러한 문제를 해결하고 보다 현대적인 방식으로 파일 및 디렉터리를 조작할 수 있도록 돕습니다.
본 기사에서는 std::filesystem
을 활용하여 파일 및 디렉터리를 다루는 다양한 방법을 소개하며, 크로스 플랫폼 개발에서 활용할 수 있는 실용적인 예제들을 제공할 것입니다.
std::filesystem 개요
C++17에 도입된 std::filesystem
은 파일 시스템을 조작하기 위한 표준 라이브러리입니다. 이 라이브러리는 플랫폼 독립적인 방식으로 파일과 디렉터리를 관리할 수 있도록 지원하며, 복잡한 경로 처리를 간소화하는 기능을 제공합니다.
std::filesystem의 주요 기능
std::filesystem
을 활용하면 다음과 같은 파일 시스템 작업을 수행할 수 있습니다.
- 파일 및 디렉터리 조작: 생성, 삭제, 이동, 복사 등
- 파일 속성 조회: 크기, 마지막 수정 시간, 권한 정보 확인
- 디렉터리 탐색: 특정 경로 내 파일 목록 조회 및 필터링
- 경로(path) 변환: OS별 파일 경로 차이 해결
헤더 파일 및 네임스페이스
std::filesystem
을 사용하려면 <filesystem>
헤더를 포함해야 하며, C++의 std::filesystem
네임스페이스를 사용해야 합니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path myPath{"example.txt"};
std::cout << "파일 경로: " << myPath << std::endl;
return 0;
}
위 코드에서 fs::path
를 사용하여 파일 경로를 지정하고 출력할 수 있습니다.
플랫폼 독립적 파일 조작
기존에는 운영체제마다 다른 방식으로 파일 시스템을 다루어야 했지만, std::filesystem
을 사용하면 Windows, Linux, macOS에서 동일한 코드로 파일 조작이 가능합니다.
이제 std::filesystem
을 활용하여 실제로 파일 및 디렉터리를 조작하는 방법을 알아보겠습니다.
파일 및 디렉터리 조작 기본
C++17의 std::filesystem
을 사용하면 간단한 코드로 파일 및 디렉터리를 조작할 수 있습니다. 파일 생성, 삭제, 이동, 복사 등의 작업을 수행하는 방법을 살펴보겠습니다.
파일 생성 및 삭제
파일을 생성하거나 삭제하는 가장 간단한 방법은 std::ofstream
과 std::filesystem::remove
를 사용하는 것입니다.
#include <iostream>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
int main() {
std::string filename = "example.txt";
// 파일 생성
std::ofstream file(filename);
if (file) {
std::cout << filename << " 파일이 생성되었습니다." << std::endl;
}
file.close();
// 파일 삭제
if (fs::remove(filename)) {
std::cout << filename << " 파일이 삭제되었습니다." << std::endl;
} else {
std::cout << filename << " 파일을 찾을 수 없습니다." << std::endl;
}
return 0;
}
위 코드에서는 std::ofstream
을 이용해 파일을 생성한 후, fs::remove()
를 사용하여 파일을 삭제합니다.
디렉터리 생성 및 삭제
디렉터리는 fs::create_directory()
와 fs::remove_all()
을 이용하여 생성 및 삭제할 수 있습니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string dirName = "test_directory";
// 디렉터리 생성
if (fs::create_directory(dirName)) {
std::cout << dirName << " 디렉터리가 생성되었습니다." << std::endl;
}
// 디렉터리 삭제
if (fs::remove_all(dirName)) {
std::cout << dirName << " 디렉터리가 삭제되었습니다." << std::endl;
}
return 0;
}
위 코드에서 fs::create_directory()
는 지정된 이름의 디렉터리를 생성하며, fs::remove_all()
은 디렉터리와 그 안의 모든 파일을 삭제합니다.
파일 및 디렉터리 이동 및 복사
파일 및 디렉터리는 fs::rename()
으로 이동할 수 있으며, fs::copy()
를 사용해 복사할 수도 있습니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
std::string srcFile = "source.txt";
std::string destFile = "destination.txt";
// 파일 이동 (이름 변경)
fs::rename(srcFile, destFile);
std::cout << srcFile << " → " << destFile << " 이동 완료" << std::endl;
// 파일 복사
fs::copy(destFile, "copy.txt");
std::cout << destFile << " → copy.txt 복사 완료" << std::endl;
return 0;
}
위 코드에서는 fs::rename()
을 이용해 파일 이름을 변경하며, fs::copy()
를 사용해 파일을 복사합니다.
디렉터리 복사
디렉터리를 복사하려면 fs::copy()
에 fs::copy_options::recursive
옵션을 추가해야 합니다.
fs::copy("source_directory", "backup_directory", fs::copy_options::recursive);
이제 std::filesystem
을 활용한 파일 및 디렉터리 조작 방법을 익혔으므로, 다음으로 경로(path) 처리를 살펴보겠습니다.
경로(path) 처리와 변환
C++17의 std::filesystem::path
는 파일 및 디렉터리 경로를 다룰 때 유용한 클래스로, 운영체제에 따라 달라지는 경로 구분자를 자동으로 처리하고 다양한 변환 기능을 제공합니다.
경로 객체 생성 및 출력
std::filesystem::path
객체를 사용하면 파일 또는 디렉터리 경로를 쉽게 다룰 수 있습니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath("C:/Users/Example/file.txt");
std::cout << "파일 경로: " << filePath << std::endl;
std::cout << "파일명: " << filePath.filename() << std::endl;
std::cout << "확장자: " << filePath.extension() << std::endl;
std::cout << "부모 디렉터리: " << filePath.parent_path() << std::endl;
return 0;
}
위 코드에서는 filename()
, extension()
, parent_path()
등의 메서드를 사용하여 경로의 구성 요소를 추출할 수 있습니다.
경로 결합
경로를 결합할 때는 /
연산자를 사용하거나 append()
메서드를 활용할 수 있습니다.
fs::path dir = "C:/Users/Example";
fs::path fullPath = dir / "Documents" / "file.txt";
std::cout << "전체 경로: " << fullPath << std::endl;
또는 append()
를 사용할 수도 있습니다.
fs::path base = "C:/Users";
base.append("Example").append("Documents").append("file.txt");
std::cout << "전체 경로: " << base << std::endl;
경로 변환
플랫폼에 따라 적절한 형식으로 경로를 변환하는 기능도 제공합니다.
fs::path unixPath("/home/user/file.txt");
fs::path winPath("C:\\Users\\file.txt");
std::cout << "유니코드 문자열 변환: " << unixPath.u8string() << std::endl;
std::cout << "네이티브 형식 변환: " << winPath.native() << std::endl;
u8string()
, wstring()
, native()
등의 메서드를 활용하면 UTF-8 문자열이나 네이티브 운영체제 형식으로 변환할 수 있습니다.
절대 경로 변환
상대 경로를 절대 경로로 변환하려면 absolute()
함수를 사용합니다.
fs::path relativePath("myfile.txt");
fs::path absolutePath = fs::absolute(relativePath);
std::cout << "절대 경로: " << absolutePath << std::endl;
경로 비교
경로가 같은지 비교할 때는 ==
연산자를 사용하면 됩니다.
fs::path path1("C:/Users/Example/file.txt");
fs::path path2("C:/Users/Example/file.txt");
if (path1 == path2) {
std::cout << "경로가 동일합니다." << std::endl;
}
이제 경로를 효과적으로 다룰 수 있는 방법을 배웠습니다. 다음으로 파일 속성 및 권한을 제어하는 방법을 알아보겠습니다.
파일 속성 및 권한 제어
C++17의 std::filesystem
을 사용하면 파일 크기, 수정 시간, 권한 등을 쉽게 조회하고 변경할 수 있습니다. 이를 활용하면 프로그램에서 파일의 상태를 확인하거나, 보안 및 접근 권한을 조절할 수 있습니다.
파일 크기 확인
std::filesystem::file_size()
를 사용하면 파일의 크기를 바이트 단위로 확인할 수 있습니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "example.txt";
if (fs::exists(filePath)) {
std::cout << "파일 크기: " << fs::file_size(filePath) << " 바이트" << std::endl;
} else {
std::cout << "파일이 존재하지 않습니다." << std::endl;
}
return 0;
}
위 코드에서 fs::exists()
로 파일의 존재 여부를 확인한 후 fs::file_size()
를 사용하여 크기를 출력합니다.
파일의 마지막 수정 시간 조회
파일의 마지막 수정 시간을 가져오려면 last_write_time()
을 사용합니다.
#include <iostream>
#include <filesystem>
#include <chrono>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "example.txt";
if (fs::exists(filePath)) {
auto ftime = fs::last_write_time(filePath);
auto cftime = decltype(ftime)::clock::to_time_t(ftime);
std::cout << "마지막 수정 시간: " << std::ctime(&cftime);
} else {
std::cout << "파일이 존재하지 않습니다." << std::endl;
}
return 0;
}
last_write_time()
을 사용하면 파일의 수정 시간을 가져올 수 있으며, 이를 std::ctime()
을 이용해 사람이 읽을 수 있는 형식으로 변환할 수 있습니다.
파일 권한 확인 및 변경
파일의 접근 권한을 확인하고 변경하는 데 fs::status()
와 fs::permissions()
를 사용할 수 있습니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "example.txt";
// 파일 권한 확인
fs::perms p = fs::status(filePath).permissions();
if ((p & fs::perms::owner_read) != fs::perms::none) {
std::cout << "파일을 읽을 수 있습니다." << std::endl;
}
if ((p & fs::perms::owner_write) != fs::perms::none) {
std::cout << "파일을 쓸 수 있습니다." << std::endl;
}
return 0;
}
위 코드에서는 fs::status(filePath).permissions()
를 통해 파일 권한을 확인합니다.
파일 권한 변경
파일의 읽기 및 쓰기 권한을 변경하려면 fs::permissions()
함수를 사용합니다.
fs::permissions("example.txt", fs::perms::owner_read | fs::perms::owner_write);
위 코드는 파일 소유자가 읽기 및 쓰기 권한을 가지도록 설정합니다.
또한, 특정 권한을 추가하거나 제거할 수도 있습니다.
fs::permissions("example.txt", fs::perms::owner_write, fs::perm_options::remove);
이렇게 하면 파일의 쓰기 권한이 제거됩니다.
파일 유형 확인
파일이 일반 파일인지, 디렉터리인지 확인하려면 fs::is_regular_file()
과 fs::is_directory()
를 사용할 수 있습니다.
if (fs::is_regular_file("example.txt")) {
std::cout << "일반 파일입니다." << std::endl;
}
if (fs::is_directory("example_directory")) {
std::cout << "디렉터리입니다." << std::endl;
}
위 기능들을 활용하면 파일 속성을 손쉽게 조회하고 관리할 수 있습니다. 다음으로는 파일 탐색과 반복자를 활용하는 방법을 살펴보겠습니다.
파일 탐색 및 반복자 활용
C++17의 std::filesystem
을 사용하면 디렉터리 내 파일을 효율적으로 탐색할 수 있습니다. 이를 통해 특정 확장자를 가진 파일을 검색하거나, 서브디렉터리를 포함한 전체 파일 목록을 가져올 수 있습니다.
디렉터리 내 파일 목록 출력
디렉터리 내 파일과 폴더를 나열하려면 std::filesystem::directory_iterator
를 사용합니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path dirPath = "example_directory";
if (fs::exists(dirPath) && fs::is_directory(dirPath)) {
std::cout << dirPath << " 내 파일 목록:" << std::endl;
for (const auto& entry : fs::directory_iterator(dirPath)) {
std::cout << entry.path() << std::endl;
}
} else {
std::cout << "디렉터리가 존재하지 않습니다." << std::endl;
}
return 0;
}
위 코드는 지정한 디렉터리 내의 모든 파일과 하위 폴더를 출력합니다.
서브디렉터리 포함 전체 탐색
디렉터리 내부를 재귀적으로 탐색하려면 recursive_directory_iterator
를 사용합니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path dirPath = "example_directory";
if (fs::exists(dirPath) && fs::is_directory(dirPath)) {
std::cout << dirPath << " 내 모든 파일 및 폴더:" << std::endl;
for (const auto& entry : fs::recursive_directory_iterator(dirPath)) {
std::cout << entry.path() << std::endl;
}
} else {
std::cout << "디렉터리가 존재하지 않습니다." << std::endl;
}
return 0;
}
위 코드는 디렉터리 내부의 모든 파일과 서브디렉터리를 포함하여 탐색하는 방법을 보여줍니다.
특정 확장자의 파일만 검색
특정 확장자를 가진 파일만 찾고 싶다면 .extension()
을 활용할 수 있습니다.
fs::path dirPath = "example_directory";
std::string targetExt = ".txt";
for (const auto& entry : fs::directory_iterator(dirPath)) {
if (entry.path().extension() == targetExt) {
std::cout << "TXT 파일: " << entry.path() << std::endl;
}
}
위 코드는 .txt
확장자를 가진 파일만 출력합니다.
파일 탐색 최적화
- 대량 파일 처리:
directory_iterator
는 필요할 때만 파일을 로드하므로 성능이 좋음 - 재귀 탐색 시
depth()
활용: 너무 깊은 탐색을 방지하려면depth()
를 활용 - 대용량 데이터 검색: 대용량 폴더 탐색 시 멀티스레딩 고려 가능
이제 std::filesystem
을 활용한 파일 탐색 방법을 익혔으므로, 다음으로 파일 스트림과 연계하는 방법을 살펴보겠습니다.
std::filesystem과 파일 스트림 연계
C++17의 std::filesystem
을 std::ifstream
, std::ofstream
과 함께 사용하면 파일을 더욱 직관적으로 다룰 수 있습니다. 이를 통해 파일의 존재 여부를 확인하고, 안전하게 파일을 읽고 쓸 수 있습니다.
파일 존재 여부 확인 후 열기
파일을 열기 전에 fs::exists()
를 사용하여 존재 여부를 확인하면 파일 작업의 안전성을 높일 수 있습니다.
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "example.txt";
if (fs::exists(filePath)) {
std::ifstream file(filePath);
std::cout << "파일이 존재하며, 열었습니다." << std::endl;
} else {
std::cout << "파일이 존재하지 않습니다." << std::endl;
}
return 0;
}
위 코드에서는 파일이 존재하는 경우에만 열도록 처리했습니다.
파일 생성 및 쓰기
파일을 생성하고 데이터를 기록하는 예제입니다.
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "output.txt";
std::ofstream outFile(filePath);
if (outFile) {
outFile << "std::filesystem과 파일 스트림 연계 예제입니다." << std::endl;
std::cout << "파일 생성 및 데이터 기록 완료!" << std::endl;
} else {
std::cout << "파일을 생성할 수 없습니다." << std::endl;
}
return 0;
}
위 코드에서는 std::ofstream
을 사용하여 새 파일을 생성하고 데이터를 기록했습니다.
파일 읽기
파일의 내용을 읽어 출력하는 코드입니다.
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "output.txt";
if (fs::exists(filePath)) {
std::ifstream inFile(filePath);
std::string line;
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
} else {
std::cout << "파일이 존재하지 않습니다." << std::endl;
}
return 0;
}
이 코드는 파일이 존재하면 내용을 한 줄씩 읽어 출력합니다.
파일 크기를 확인한 후 읽기
파일이 비어 있는지 확인한 후 읽는 방법입니다.
if (fs::exists(filePath) && fs::file_size(filePath) > 0) {
std::ifstream inFile(filePath);
std::string content((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
std::cout << "파일 내용:\n" << content << std::endl;
} else {
std::cout << "파일이 비어 있거나 존재하지 않습니다." << std::endl;
}
파일 크기가 0보다 클 때만 읽도록 하여 불필요한 처리를 방지합니다.
파일 스트림과 경로 변환
std::filesystem::path
객체를 std::ofstream
및 std::ifstream
에 직접 전달할 수 있습니다.
fs::path logFile = "logs/app.log";
std::ofstream logStream(logFile, std::ios::app);
logStream << "로그 기록: 프로그램 실행됨." << std::endl;
이 방식은 운영체제의 파일 경로 형식과 무관하게 동작합니다.
파일 스트림과 std::filesystem의 장점
std::filesystem
을 사용하면 파일 존재 여부를 사전에 확인하여 오류를 방지할 수 있음std::path
를 활용하면 운영체제에 따라 경로 형식을 일일이 맞출 필요가 없음file_size()
와 함께 활용하면 대용량 파일을 효율적으로 처리할 수 있음
이제 파일 스트림과 std::filesystem
을 연계하는 방법을 익혔습니다. 다음으로는 예외 처리 및 오류 대응 방법을 살펴보겠습니다.
예외 처리 및 오류 대응
C++17의 std::filesystem
을 사용할 때 파일이 존재하지 않거나, 읽기/쓰기 권한이 없거나, 디스크 공간이 부족한 경우 예외가 발생할 수 있습니다. 이러한 오류를 안전하게 처리하려면 try-catch
블록과 std::error_code
를 활용해야 합니다.
예외 발생 시 잡아내기
std::filesystem
의 일부 함수는 예외를 던지므로, 반드시 try-catch
로 감싸서 처리해야 합니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
try {
fs::path invalidPath = "invalid_directory";
// 존재하지 않는 디렉터리를 삭제하려고 하면 예외 발생
fs::remove(invalidPath);
std::cout << "디렉터리가 삭제되었습니다." << std::endl;
} catch (const fs::filesystem_error& e) {
std::cerr << "파일 시스템 오류 발생: " << e.what() << std::endl;
}
return 0;
}
위 코드에서 존재하지 않는 디렉터리를 삭제하려 하면 예외가 발생하며, 이를 catch
블록에서 잡아 메시지를 출력합니다.
std::error_code를 활용한 안전한 오류 처리
예외가 발생하지 않도록 std::error_code
를 사용하면 보다 안전하게 오류를 확인할 수 있습니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path dirPath = "example_directory";
std::error_code ec;
// 디렉터리 생성 시 오류 코드 사용
if (!fs::create_directory(dirPath, ec)) {
std::cerr << "디렉터리 생성 실패: " << ec.message() << std::endl;
} else {
std::cout << "디렉터리 생성 완료!" << std::endl;
}
return 0;
}
이 코드에서는 fs::create_directory()
를 실행할 때 예외를 발생시키지 않고 std::error_code
를 통해 오류 여부를 확인합니다.
파일 열기 시 오류 처리
파일을 열 때도 std::filesystem
을 활용하여 안전하게 오류를 처리할 수 있습니다.
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = "readonly.txt";
std::ifstream inFile(filePath);
if (!inFile) {
std::cerr << "파일을 열 수 없습니다: " << filePath << std::endl;
return 1;
}
std::cout << "파일을 성공적으로 열었습니다." << std::endl;
return 0;
}
위 코드에서는 파일이 존재하지 않거나 읽기 권한이 없을 경우 오류 메시지를 출력합니다.
파일 복사 시 오류 처리
파일을 복사하는 경우 파일이 존재하지 않거나 대상 파일이 이미 존재할 경우 오류가 발생할 수 있습니다. 이를 방지하려면 std::error_code
를 사용합니다.
fs::path src = "source.txt";
fs::path dest = "destination.txt";
std::error_code ec;
fs::copy(src, dest, fs::copy_options::skip_existing, ec);
if (ec) {
std::cerr << "파일 복사 실패: " << ec.message() << std::endl;
} else {
std::cout << "파일 복사 성공!" << std::endl;
}
이렇게 하면 대상 파일이 이미 존재할 경우 오류를 방지하고, 필요에 따라 다른 복사 옵션을 설정할 수 있습니다.
파일 시스템 오류를 효과적으로 처리하는 방법
- 가능한 예외를 예상하고 try-catch 블록을 사용
- 오류 코드(std::error_code)를 활용하여 예외 발생을 피함
- 파일 및 디렉터리 존재 여부를 사전에 확인 (
fs::exists()
활용) - 권한 문제를 사전에 검사 (
fs::status()
와fs::perms
활용)
이제 std::filesystem
을 사용할 때 발생할 수 있는 예외를 효과적으로 처리하는 방법을 익혔습니다. 다음으로는 크로스 플랫폼 호환성을 고려하여 파일 시스템을 다루는 방법을 살펴보겠습니다.
크로스 플랫폼 호환성 고려 사항
C++17의 std::filesystem
은 Windows, Linux, macOS에서 동일한 API를 제공하지만, 운영체제별 파일 시스템 차이로 인해 호환성 문제가 발생할 수 있습니다. 본 섹션에서는 크로스 플랫폼 파일 시스템 프로그래밍 시 고려해야 할 주요 사항을 다룹니다.
경로 구분자 차이
운영체제마다 경로 구분자가 다릅니다.
- Windows:
C:\Users\Example\file.txt
(백슬래시\
사용) - Linux/macOS:
/home/example/file.txt
(슬래시/
사용)
std::filesystem::path
를 사용하면 OS에 맞게 자동 변환됩니다.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path filePath = fs::path("C:/Users/Example/file.txt"); // OS에 맞게 변환됨
std::cout << "네이티브 경로: " << filePath.native() << std::endl;
return 0;
}
따라서 경로를 문자열로 직접 지정하는 것보다 fs::path
객체를 사용하는 것이 좋습니다.
파일 경로 인코딩 차이
Windows에서는 기본적으로 UTF-16, Linux/macOS는 UTF-8을 사용합니다.
Windows에서 유니코드 경로 지원
fs::path winPath = L"C:\\사용자\\문서\\파일.txt"; // 유니코드 경로
std::wcout << L"경로: " << winPath << std::endl;
Windows에서 경로를 다룰 때는 wchar_t
를 사용해야 합니다.
Linux/macOS에서 UTF-8 문자열 사용
fs::path unixPath = u8"/home/사용자/문서/파일.txt";
std::cout << "경로: " << unixPath.u8string() << std::endl;
UTF-8 문자열을 사용하면 멀티바이트 문자(예: 한글) 경로를 처리할 수 있습니다.
파일 권한 차이
Linux/macOS는 POSIX 권한 모델을 사용하지만, Windows는 ACL(Access Control List) 기반입니다.
파일 권한을 확인하려면 다음을 사용합니다.
fs::perms permissions = fs::status("example.txt").permissions();
if ((permissions & fs::perms::owner_read) != fs::perms::none) {
std::cout << "읽기 가능" << std::endl;
}
하지만 Windows에서는 권한이 다르게 해석될 수 있습니다. 따라서 Windows의 파일 권한을 변경하려면 SetFileSecurity()
같은 API를 사용해야 합니다.
파일 속성 조회 차이
Windows에서는 숨김 파일(hidden attribute)을 사용하며, Linux/macOS에서는 파일명이 .
으로 시작하면 숨김 파일로 간주됩니다.
Windows에서 파일이 숨김인지 확인하는 방법:
#ifdef _WIN32
#include <windows.h>
bool isHidden(const fs::path& path) {
DWORD attrs = GetFileAttributesW(path.c_str());
return (attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_HIDDEN);
}
#endif
Linux/macOS에서 파일이 숨김인지 확인하는 방법:
bool isHidden(const fs::path& path) {
return path.filename().string().front() == '.';
}
파일 시스템 유형 확인
운영체제별로 파일 시스템이 다르므로, 특정 기능(예: 심볼릭 링크, 압축 속성 등)이 지원되지 않을 수 있습니다.
fs::space_info diskInfo = fs::space("/");
std::cout << "전체 용량: " << diskInfo.capacity << " 바이트" << std::endl;
std::cout << "사용 가능 용량: " << diskInfo.available << " 바이트" << std::endl;
위 코드는 리눅스와 macOS에서 사용 가능하지만, Windows에서는 드라이브 문자를 지정해야 합니다.
크로스 플랫폼 개발 시 고려할 사항
- 경로 처리는 항상
std::filesystem::path
를 사용할 것 - 파일 경로의 인코딩 차이를 고려할 것 (UTF-8 vs UTF-16)
- 권한 관리는 OS별로 다르게 처리해야 함
- 숨김 파일 및 속성 차이를 반영할 것
- 파일 시스템 유형에 따라 다른 동작을 할 수 있도록 대비할 것
이제 std::filesystem
을 활용하여 크로스 플랫폼에서 호환성을 유지하는 방법을 배웠습니다. 다음으로 전체 내용을 정리하는 요약 섹션을 살펴보겠습니다.
요약
본 기사에서는 C++17의 std::filesystem
을 활용하여 크로스 플랫폼에서 파일과 디렉터리를 효과적으로 조작하는 방법을 살펴보았습니다.
- 기본 개념:
std::filesystem
을 사용하면 파일 및 디렉터리 작업을 플랫폼 독립적으로 수행할 수 있습니다. - 파일 및 디렉터리 조작: 생성, 삭제, 이동, 복사 등의 작업을 쉽게 처리할 수 있습니다.
- 경로(path) 처리: 경로 변환, 절대/상대 경로 변환, 경로 결합 등을 지원합니다.
- 파일 속성 및 권한 제어: 파일 크기, 수정 시간, 권한을 확인하고 변경할 수 있습니다.
- 파일 탐색:
directory_iterator
와recursive_directory_iterator
를 활용하여 파일 목록을 검색할 수 있습니다. - 파일 스트림 연계:
std::ifstream
및std::ofstream
과std::filesystem
을 결합하여 안전한 파일 입출력을 구현할 수 있습니다. - 예외 처리 및 오류 대응:
try-catch
및std::error_code
를 활용하여 안전한 파일 시스템 작업을 수행할 수 있습니다. - 크로스 플랫폼 호환성: 운영체제별 차이점을 고려하여 코드의 이식성을 높일 수 있습니다.
이제 std::filesystem
을 활용하여 파일 시스템 작업을 더욱 효율적으로 수행할 수 있습니다. 이를 통해 C++ 기반 애플리케이션에서 파일 및 디렉터리 관리를 손쉽게 구현할 수 있을 것입니다.