[c++] 표준 C ++에서 모든 파일 / 디렉토리를 재귀 적으로 어떻게 반복합니까?

표준 C ++에서 모든 파일 / 디렉토리를 재귀 적으로 어떻게 반복합니까?



답변

표준 C ++에서는 표준 C ++에 디렉토리 개념이 없기 때문에 기술적으로이를 수행 할 방법이 없습니다. 네트워크를 조금 확장하고 싶다면 Boost.FileSystem 을 사용하는 것이 좋습니다 . 이것은 TR2에 포함되도록 승인되었으므로 구현을 가능한 한 표준에 가깝게 유지할 수있는 최상의 기회를 제공합니다.

웹 사이트에서 직접 가져온 예 :

bool find_file( const path & dir_path,         // in this directory,
                const std::string & file_name, // search for this name,
                path & path_found )            // placing path here if found
{
  if ( !exists( dir_path ) ) return false;
  directory_iterator end_itr; // default construction yields past-the-end
  for ( directory_iterator itr( dir_path );
        itr != end_itr;
        ++itr )
  {
    if ( is_directory(itr->status()) )
    {
      if ( find_file( itr->path(), file_name, path_found ) ) return true;
    }
    else if ( itr->leaf() == file_name ) // see below
    {
      path_found = itr->path();
      return true;
    }
  }
  return false;
}


답변

C ++ 17 이후부터 <filesystem>헤더 및 범위- for에서는 다음 과 같이 간단히 수행 할 수 있습니다.

#include <filesystem>

using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
...
for (const auto& dirEntry : recursive_directory_iterator(myPath))
     std::cout << dirEntry << std::endl;

C ++ 17부터는 std::filesystem표준 라이브러리의 일부이며 <filesystem>헤더 에서 찾을 수 있습니다 (더 이상 “실험용”이 아님).


답변

Win32 API를 사용하는 경우 FindFirstFileFindNextFile 함수를 사용할 수 있습니다 .

http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx

재귀 적 디렉터리 순회의 경우 각 WIN32_FIND_DATA.dwFileAttributes 를 검사하여 FILE_ATTRIBUTE_DIRECTORY 비트가 설정 되어 있는지 확인해야합니다 . 비트가 설정되면 해당 디렉토리로 함수를 재귀 적으로 호출 할 수 있습니다. 또는 재귀 호출과 동일한 효과를 제공하지만 매우 긴 경로 트리에 대한 스택 오버플로를 방지하기 위해 스택을 사용할 수 있습니다.

#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>

using namespace std;

bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA ffd;
    wstring spec;
    stack<wstring> directories;

    directories.push(path);
    files.clear();

    while (!directories.empty()) {
        path = directories.top();
        spec = path + L"\\" + mask;
        directories.pop();

        hFind = FindFirstFile(spec.c_str(), &ffd);
        if (hFind == INVALID_HANDLE_VALUE)  {
            return false;
        } 

        do {
            if (wcscmp(ffd.cFileName, L".") != 0 && 
                wcscmp(ffd.cFileName, L"..") != 0) {
                if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    directories.push(path + L"\\" + ffd.cFileName);
                }
                else {
                    files.push_back(path + L"\\" + ffd.cFileName);
                }
            }
        } while (FindNextFile(hFind, &ffd) != 0);

        if (GetLastError() != ERROR_NO_MORE_FILES) {
            FindClose(hFind);
            return false;
        }

        FindClose(hFind);
        hFind = INVALID_HANDLE_VALUE;
    }

    return true;
}

int main(int argc, char* argv[])
{
    vector<wstring> files;

    if (ListFiles(L"F:\\cvsrepos", L"*", files)) {
        for (vector<wstring>::iterator it = files.begin(); 
             it != files.end(); 
             ++it) {
            wcout << it->c_str() << endl;
        }
    }
    return 0;
}


답변

새로운 C ++ 11 범위 기반 forBoost를 사용하면 더 간단하게 만들 수 있습니다 .

#include <boost/filesystem.hpp>

using namespace boost::filesystem;    
struct recursive_directory_range
{
    typedef recursive_directory_iterator iterator;
    recursive_directory_range(path p) : p_(p) {}

    iterator begin() { return recursive_directory_iterator(p_); }
    iterator end() { return recursive_directory_iterator(); }

    path p_;
};

for (auto it : recursive_directory_range(dir_path))
{
    std::cout << it << std::endl;
}


답변

빠른 솔루션은 C의 Dirent.h 라이브러리를 사용하는 것입니다.

Wikipedia의 작업 코드 조각 :

#include <stdio.h>
#include <dirent.h>

int listdir(const char *path) {
    struct dirent *entry;
    DIR *dp;

    dp = opendir(path);
    if (dp == NULL) {
        perror("opendir: Path does not exist or could not be read.");
        return -1;
    }

    while ((entry = readdir(dp)))
        puts(entry->d_name);

    closedir(dp);
    return 0;
}


답변

위에서 언급 한 boost :: filesystem 외에도 wxWidgets :: wxDirQt :: QDir 을 검사 할 수 있습니다 .

wxWidget과 Qt는 모두 오픈 소스, 크로스 플랫폼 C ++ 프레임 워크입니다.

wxDirTraverse()또는 더 간단한 GetAllFiles()기능을 사용하여 파일을 재귀 적으로 순회하는 유연한 방법을 제공 합니다. 또한 GetFirst()GetNext()함수를 사용 하여 순회를 구현할 수 있습니다 (Traverse () 및 GetAllFiles ()는 결국 GetFirst () 및 GetNext () 함수를 사용하는 래퍼라고 가정합니다).

QDir디렉토리 구조와 그 내용에 대한 액세스를 제공합니다. QDir을 사용하여 디렉토리를 탐색하는 방법에는 여러 가지가 있습니다. QDirIterator :: Subdirectories 플래그로 인스턴스화 된 QDirIterator를 사용하여 디렉토리 내용 (하위 디렉토리 포함)을 반복 할 수 있습니다. 또 다른 방법은 QDir의 GetEntryList () 함수를 사용하고 재귀 적 순회를 구현하는 것입니다.

여기에 (에서 가져온 샘플 코드 여기 쇼가 어떻게 모든 하위 디렉토리를 반복하는 것을 # 예 8-5).

#include <qapplication.h>
#include <qdir.h>
#include <iostream>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    QDir currentDir = QDir::current();

    currentDir.setFilter( QDir::Dirs );
    QStringList entries = currentDir.entryList();
    for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
    {
         std::cout << *entry << std::endl;
    }
    return 0;
}


답변

Boost :: filesystem은 recursive_directory_iterator를 제공하므로이 작업에 매우 편리합니다.

#include "boost/filesystem.hpp"
#include <iostream>

using namespace boost::filesystem;

recursive_directory_iterator end;
for (recursive_directory_iterator it("./"); it != end; ++it) {
    std::cout << *it << std::endl;
}