본문 바로가기

별걸다하는 IT/프로그래밍언어

[C++ 윈도우 API] 특정 경로에 있는 파일 폴더 목록 가져오기 소스코드 (FindFirstFile, FindNextFile, FindClose)

안녕하세요 양햄찌 블로그 주인장입니다.

리눅스/유닉스의 경우 dirent.h 헤더파일을 지원해줘서 opendir, readdir 등등 여러 함수로 디렉터리 접근이 가능하죠 ㅎㅎ

하지만 이는 리눅스/유닉스에서 동작하는 라이브러리일뿐... 윈도우에는 적용되지 않는 다는 것..!

그래서 오늘은 윈도우 운영체제에서 작동하는 WIN32 API로 특정 디렉터리에 있는 파일 리스트를 소스로 작성해보려고 합니다.

윈도우 운영체제에서 디렉터리 파일 목록 가져오기

오늘 사용해볼 함수는 이렇게 3개입니다.

FindFirstFile로 첫 번째 파일을 찾고 첫 번째 파일부터 반복문을 돌려 FindNextFile로 다음 파일들을 출력해볼거예요.

그 다음에 FindClose로 핸들을 닫아줄거랍니다.

 

전체 소스코드만 필요하신 분은 맨 밑으로~

헤더 파일

요 함수들은 WIN32 API로 windows.h 라이브러리에 포함되어있습니다.

#include <windows.h>

인클루드 해줍시다.

 

FindFirstFile 함수 

♤ 함수 정의

FIndFirstFIle은 파일명/경로에 해당하는 lpFileName과 결과를 전달받을 lpFindFileData 이렇게 매개변수가 2개 있습니다.

 

 함수 사용예시

HANDLE hFind = FindFirstFile("경로", &data); 

간단하쥬?

 

 리턴값

[성공]

성공하면 FindNextFile이나 FindClose를 사용하는데 필요한 Find 핸들이 리턴됩니다.

핸들은 윈도우에서 사용하는 인스턴스 식별번호 같은거죠.

 

[실패]

함수가 수행되는데 실패하면 INVALID_HANDLE_VALUE를 반환하고 

찾는 파일이 없을 경우에는 ERROR_FILE_NOT_FOUND가 반환됩니다.

if (hFind == INVALID_HANDLE_VALUE)
     throw std::runtime_error("FindFirstFile 실패");

요런 예외처리 로직 해주면 좋겠죠?

 

 간단한 테스트

#include <iostream>
#include <Windows.h>
int main()
{
    WIN32_FIND_DATAA  data;
    HANDLE hFind = FindFirstFileA("C:\\Program Files\\*", &data);
    std::cout << std::string(data.cFileName) << std::endl;
}

함수를 사용하고 그 결과값을 출력해봤어요.

아 함수뒤에 A가 붙는건 ANSI타입 문자열을 사용하겠다는 의미가 붙어있습니다. 그래서 보면 함수명이 동일한대 뒤에 A가 붙는게 있고 W가 붙는게 있고 그래요.

함수를 수행하기 전에 cmd창으로 결과값을 예측해봅시다.

dir은 파일이나 폴더 리스트를 출력해주는 CMD 명령어예요.

가장 첫 번째 파일로 '.'이 출력되어야 함을 알 수 있습니다.

실제 소스코드를 보면 '.'이 잘 출력됨을 확인할 수 있어요. 참고로 '.'는 작업경로를 의미하고 '..'는 부모 디렉터리를 의미합니다.

 

FindNextFile 함수 

♤ 함수 정의

FindFirstFile처럼 두 번째 인자에 결과를 받을 객체를 넣어줍니다.

 

 함수 사용예시

bool hasfile = FindNextFileA(hFind, &data);

hFind에는 FindFirstFile에서 리턴받은 핸들을 넣어주면 됩니다.

 

 리턴값

실패하면 0을 리턴합니다. 성공하면 0이 아닌 값 리턴

 

FindClose 함수 

♤ 함수 정의

자원 다 사용하고 나면 CLOSE해주면 됩니다.

 

 함수 사용예시

FindClose(hFind);

닫는거 까먹지 말기~ 끝!

 

파일이나 디렉터리 목록 가져오는 소스코드

위의 함수에 쪼끔 추가해서~ 파일목록, 디렉터리 목록 따로 가져와볼거예요.

#include <iostream>
#include <Windows.h>
#include <vector>
#include <stdlib.h>
int main()
{
    WIN32_FIND_DATAA  data;
    std::vector<std::string> file_list;
    std::vector<std::string> dir_list;

    try {
    	HANDLE hFind = FindFirstFileA("C:\\*", &data); //첫번째 파일 찾아 핸들 리턴
        if (hFind == INVALID_HANDLE_VALUE)
            throw std::runtime_error("FindFirstFile 실패"); //예외처리 

        while (FindNextFileA(hFind, &data))
        {
            if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&  //디렉터리라면 
                !(data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) //시스템파일은 제외
            {
                dir_list.push_back(std::string(data.cFileName));
            }
            else if ((data.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&  //파일이라면
                    !(data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) //시스템파일은 제외
            {
                file_list.push_back(std::string(data.cFileName));
            }
        }
        FindClose(hFind); //핸들 닫아주기 
    }
    catch (std::runtime_error e)
    {
        std::cerr << e.what() << std::endl;
        return -1;
    }

    //출력으로 확인하기 
    std::cout << "파일리스트" << std::endl;
    for (std::string str : file_list)
    {
        std::cout << str << std::endl;
    }
    std::cout << "디렉터리리스트" << std::endl;
    for (std::string str : dir_list)
    {
        std::cout << str << std::endl;
    }
	return 0;
}

앞에서 다 설명한 함수일텐데 dwFileAttributes 속성만 처음 볼 거예요. 해당 속성은 파일의 타입을 저장하고 있는 속성입니다. 이를 통해 원하는 파일타입만 골라서 수행할 수 있어요. (디렉터리도 일종의 파일~)

 

오늘 포스팅은 여기까지입니다. 도움이 되셨다면 공감 어떤가요?!

그럼 다음에 또 봐요~