본문 바로가기
컴퓨터/C++_STL

파일 목록 가져 오기 일반화 시키기

by adnoctum 2010. 1. 9.

      python의 glob과 같은 기능, 즉 정해진 경로 안에 있는 파일 목록을 모두 얻어 오는 기능은 빈번하게 사용되는 기능임에도 불구하고 STL이나 MFC/API에는 이에 관한 기능이 하나의 함수로 제공되지 않는 것으로 보인다. 대신 FindFirstFile, FindNextFile API를 이용하여 파일 목록을 얻어갈 수는 있다.

   파일 목록을 얻어갈 때, 얻어 갈 파일의 속성으로 주로 확장자를 사용하는 경우가 많다. 즉, 확장자가 jpg 인 것이나 txt 인 것들을 얻어가는 경우처럼. 또는 특정 파일 속성, 가령 FILE_ATTRIBUTE_ARCHIVE와 같은 속성을 검사할 수도 있기는 한데, 어쨌거나 파일의 특성에 대하여 확장자나 이러한 속성만을 사용하여 파일 목록을 얻어간다는 것은 융통성이 없다.

   FindFirstFile, FindNextFile 을 사용하여 파일 목록을 얻어 가는 과정을 생각해 보자. 필터에 맞는 파일을 찾아서 무조건 결과에 반환하도록 구현하곤 한다. 그러나 이 때, 각각의 파일 이름을 파라미터로 넘겨서 이 파일을 과연 결과에 포함시킬 것인가 말 것인가를 결정하는 함수를 파라미터로 받는다면 훨씬 편할 것이다. 물론 필터에 맞는 것을 무조건 고르고 싶다면 NULL을 넘겨 주고. 또한, 종종 더이상 파일 목록을 검사하지 않고 종료해야 할 경우도 있으므로 이에 대한 함수 역시 파라미터로 받으면 좋을 것이다. 실제로 나는 이미지 파일이 몇 개 있나를 검사하고, 10개 이상 있으면 더이상 검사하지 않고 종료해야 하는 경우가 있었다.

지금까지의 생각을 코드로 나타내면 다음과 같다.



bool GetFileNameList(

    const std::string& root_path,

    const std::string& filter,

    std::vector<std::string> *dest,

    bool (*skip_checker)(const std::string&) ,

    bool (*teriminate_checker)(const std::vector<std::string>&)

    )

{

    std::string path_filter = root_path + "\\" + filter;

    WIN32_FIND_DATA fd = { 0 };

    HANDLE hSearch = INVALID_HANDLE_VALUE;

    bool bFinished = false;

    hSearch = FindFirstFile(path_filter.c_str(), &fd);

    if(hSearch != INVALID_HANDLE_VALUE){

        while(!bFinished){

            if(skip_checker != NULL){

                if((*skip_checker)(root_path + "\\" + fd.cFileName) == true){

                    dest->push_back(fd.cFileName);

                }

            }

            else{ //

                dest->push_back(fd.cFileName);

            }

            if(teriminate_checker != NULL){

                // [terminate_checker]는 더이상 파일 이름을 가져올 필요가 없을 때

                // true를 반환해야 한다.

                if((*teriminate_checker)(*dest) == true) break;

            }

            bFinished = !FindNextFile(hSearch, &fd);

        }

    }

 

    return true;

}



즉, 함수의 인자로 두 개의 함수 파라미터를 받아서, 하나는 적당한 파일인지 확인하는데 사용하고, 나머지 하나는 더이상 파일 목록을 살펴 볼 필요가 없는지 결정하는데 사용하는 것이다.

만약 확장자가 jpg, gif, png, tiff, tif 인 것을 가져오고 싶다면? 간단하다. 다음과 같이 skip_checker를 작성하고,


bool is_image_file_extension(const std::string& file_name)

{

    char ext[10] = "";

    _splitpath(file_name.c_str(), NULL, NULL, NULL, ext);

    char *valid_ext[] = { "jpg", "gif", "png", "tif", "tiff"};

 

    int i = 0;

    for(i = 0; i<5; i++){

        if(strcmp(ext, valid_ext[i]) == 0) return true;

    }

 

    return false;

}



다음과 같이 호출하면 되는 것이다.


GetFileNameList(root_path, "*", &image_file_name, is_image_file_extension, NULL);



즉, 정해진 확장자에 대해서만 true 를 반환하는 함수를 만들어서 이 함수 포인터를 인자로 넘겨 주면 되는 것이다.