Filesystem : c++ 라이브러리 (미완성)

Drakk·2021년 7월 8일
0

라이브러리

목록 보기
1/1
post-thumbnail

[ 현재 본 강좌는 미완성입니다.
계속 만들어지는중입니다!! ]

🔪라이브러리 소개

💎Filesystem은 뭐하는 라이브러리인가?

<filesystem> 라이브러리는 경로, 일반 파일 및 디렉토리와 같은 파일 시스템 및 해당 구성 요소에 대한 작업을 수행하기 위한 기능을 제공합니다.

💎Filesystem라이브러리 사용방법

<filesystem> 라이브러리는 원래 boost.filesystem으로 개발되었으며, 최종적으로 C++17에서 ISO C++에 병합되었습니다.

💎개발환경

2021-07-09기준 Windows10 Home 사용했으며, 컴파일러는 MSVC 사용했습니다.
c++버전은 20입니다.

🔪Filesystem의 모든것

💉이름공간

파일시스템의 기본적인 이름공간을 알아보자! : std::filesystem

<filesystem>에서는 기본적으로 일반 std레퍼런스와의 혼동을 막기위해서 추가로 "std::filesystem"이라는 이름공간을 만들어놨습니다.
우선 다음과 같이 생략가능 합니다.

#include <filesystem>
using namespace std::filesystem;

int main() {

}

또한, 다음과 같이 이름공간 변경이 가능합니다.
저는 이번글에서는 아래와 같이 짧게 사용할겁니다.

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

int main() {

}

💉비멤버함수

💎파일의 절대경로를 알아내자! : std::filesystem::absolute

파일의 절대경로를 알아내기위한 방법으로 <filesystem>에서는 위 함수를 제공합니다.
사용법은 간단합니다.

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

int main() {
	fs::path p = "./";
	std::cerr << fs::absolute(p);
}

저는 분명 상대경로를 입력했지만, 위 함수를 거쳐오면서 절대경로로 바뀌었습니다!

💎파일의 정식적인 절대경로를 알아내자! : std::filesystem::canonical std::filesystem::weakly_canonical

💎파일의 상대경로를 알아내자! : std::filesystem::relative std::filesystem::proximate

💉열거형

💉클래스

💎파일경로를 나타내보자! : std::filesystem::path

std::filesystem::path는 <filesystem>에서 기본적으로 파일의 경로를 다루기위해 만들어진 클래스입니다.

우선 저는 exe파일이 있는 위치에다가 "basic"이라는 폴더를 하나 만들어놨고, 그안에다가는 "test.txt"라는 텍스트파일을 만들어놨습니다.

그러면 "test.txt"라는 텍스트파일을 가리키기위해서는 어떻게 해야할까요?

#include <filesystem> //파일시스템
#include <fstream> //파일입출력
#include <iostream> //표준입출력
namespace fs = std::filesystem;

int main() {
	fs::path p = "./basic/test.txt"; //상대경로입력
	std::ofstream(p).put('a'); //ofstream을 이용해서 path객체가 가지고있는 경로에 해당하는 파일에 'a'쓰기

	std::cerr << p; //출력
}

다음과 같이 콘솔창에는 path객체가 가지고있는 실제경로와 그 경로에 알맞게
"test.txt"라는 텍스트파일에 정상적으로 'a'가 출력된것을 보실수있습니다.

💎디렉터리를 순회해보자! : std::filesystem::directory_entry std::filesystem::directory_iterator std::filesystem::recursive_directory_iterator

<filesystem>에서 여러개또는 재귀적으로 존재하는 디렉터리들을 모두 순회하는 방법은 뭐가있을까요?
가장 편하고 대표적인 방법은 std::filesystem::directory_iterator를 사용하는것입니다.

해당 클래스는 디렉터리를 비재귀적으로 순회하면서, 생성자의 인자로서 전달받은 std::filesystem::path 객체에 포함된 경로에따라 그 하위디렉터리에 포함되는 모든 파일과 디렉터리들을 순회합니다.

우선 기본적인 사용법입니다.

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

int main() {
	fs::path p = fs::current_path(); //std::filesystem::current_path();는 현재 실행되고있는 메인모듈의 파일경로를 반환합니다.
	fs::directory_iterator iter(p);

	for (auto const& i : iter)
		std::cerr << i.path() << '\n'; //해당 디렉터리및파일의 경로출력
}

다음 코드 실행시, 사진처럼 하위 디렉터리에 포함된 모든 원소들이 출력될겁니다.

우선 코드 설명부터 하겠습니다.
저가 auto를 썼지만, i의 자료형은 정확히 "std::filesystem::directory_entry"입니다.

또한, "std::filesystem::directory_iterator"는 이름에서도 짐작이 가시다시피, 반복자로서 각 디렉터리및 파일들을 가리키는 주소를 증가시키면서 순회하기 때문에 다음과 같이도 사용이 가능합니다.

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

int main() {
	fs::path p = fs::current_path();
	fs::directory_iterator iter(p);

	for (auto& i = iter; i != fs::end(iter); ++i) {
		std::cerr << i->path() << '\n';
	}
}

하지만, 여기서 나는 "./basic/"디렉터리 안에있는 "test.txt"라는 텍스트 파일까지 출력하고 싶으면은 어떻게 하면될까요?

이럴때는 "std::filesystem::recursive_directory_iterator"클래스를 사용하시면 됩니다.
다음과 같이 사용될 수 있습니다.

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

int main() {
	fs::path p = fs::current_path();
	fs::recursive_directory_iterator iter(p);

	for (auto& i = iter; i != fs::end(iter); ++i) {
		std::cerr << i->path() << '\n';
	}
}

그러면, 밑에 사진처럼 재귀적으로 모든 디렉터리를 호출이 됩니다.
보시다시피, "./basic/"디렉터리내에 포함된 "test.txt"파일도 정상적으로 순회한것을 보실 수 있습니다.

"std::filesystem::recursive_directory_iterator"클래스에 관한 원리가 궁금하신분이 있을것같아서, 직접 구현해보았습니다.

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

void recursive(fs::path const& p) {
	std::error_code ec; //예외사항을 잡아내기위한 클래스
	fs::directory_iterator iter(p, ec);
    
   	//만약 값이 없다면, 함수종료
    	//참고로, std::error_code의 value함수는 예외사항이 발생하면 0이 아닌값을 반환합니다.
	if (ec.value() != 0) return;

	for (auto& i = iter; i != fs::end(iter); ++i) {
    
    		//만약 폴더인경우, 해당경로로 함수 재귀적 호출
		if (i->is_directory()) recursive(i->path());
		std::cerr << i->path() << '\n';
	}
}

int main() {
	fs::path p = fs::current_path();
	recursive(p);
}

아마 위 코드와 같이, 재귀적인 형태로 만들어져있을겁니다.

.
.
.
[ 현재 본 강좌는 미완성입니다.
계속 만들어지는중입니다!! ]

profile
C++ / Assembly / Python 언어를 다루고 있습니다!

1개의 댓글

comment-user-thumbnail
2024년 9월 4일

마지막 파일을 알 수 있는 방법이 없을까요 ?
없으면 경로를 하나하나 섬세하게 vector에 담아 놓고 vecPath.back() 이렇게 하는거 말고는 방법이 없을까요 ?

답글 달기