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

StackOverflow https://stackoverflow.com/questions/67273

  •  09-06-2019
  •  | 
  •  

문제

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

도움이 되었습니까?

해결책

표준 C++에서는 표준 C++에는 디렉토리 개념이 없기 때문에 기술적으로 이를 수행할 수 있는 방법이 없습니다.네트워크를 조금 확장하고 싶다면 다음을 사용하는 것이 좋습니다. Boost.파일 시스템.이는 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;
}

다른 팁

Win32 API를 사용하는 경우 다음을 사용할 수 있습니다. 첫 번째 파일 찾기 그리고 다음파일찾기 기능.

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 범위 기반 for 그리고 후원:

#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;
}

"파일 시스템 TS"가 포함된 C++11/14에서는 <experimental/filesystem> 헤더 및 범위-for 간단히 이렇게 할 수 있습니다:

#include <experimental/filesystem>

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

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

빠른 솔루션은 C를 사용하는 것입니다 디렌트.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 외에도 다음을 검토할 수 있습니다. wxWidget::wxDir 그리고 Qt::QDir.

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

wxDir 다음을 사용하여 파일을 재귀적으로 탐색하는 유연한 방법을 제공합니다. Traverse() 아니면 더 간단하다 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;                                    
}

당신이 사용할 수있는 ftw(3) 또는 nftw(3) C 또는 C++에서 파일 시스템 계층 구조를 탐색하려면 POSIX 시스템.

당신은 그렇지 않습니다.C++ 표준에는 디렉토리 개념이 없습니다.문자열을 파일 핸들로 변환하는 것은 구현에 달려 있습니다.해당 문자열의 내용과 매핑되는 내용은 OS에 따라 다릅니다.C++를 사용하여 해당 OS를 작성할 수 있으므로 디렉터리를 반복하는 방법을 묻는 수준이 아직 정의되지 않은 수준에서 사용됩니다(디렉터리 관리 코드를 작성하기 때문에).

이를 수행하는 방법은 OS API 문서를 참조하십시오.휴대성이 필요하다면 여러 가지가 있어야 합니다. #ifdef다양한 OS에 대한 s.

아마도 Boost나 C++14의 실험적인 파일 시스템을 사용하는 것이 가장 좋을 것입니다. 만약에 내부 디렉터리(예:프로그램이 닫힌 후 데이터를 저장하기 위해 프로그램에 사용됨), 파일 내용의 인덱스가 있는 인덱스 파일을 만듭니다.그건 그렇고, 아마도 앞으로는 Boost를 사용해야 할 것이므로, Boost가 설치되어 있지 않다면 설치하십시오!둘째, 조건부 컴파일을 사용할 수 있습니다. 예를 들면 다음과 같습니다.

#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif

각 사례의 코드는 다음에서 가져옵니다. https://stackoverflow.com/a/67336/7077165

#ifdef POSIX //unix, linux, etc.
#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;
}
#endif
#ifdef WINDOWS
#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;
}
#endif
//so on and so forth.

파일 시스템 순회를 위해서는 OS별 함수를 호출해야 합니다. open() 그리고 readdir().C 표준은 파일 시스템 관련 기능을 지정하지 않습니다.

당신은 그렇지 않습니다.표준 C++는 디렉토리 개념을 노출하지 않습니다.특히 디렉터리의 모든 파일을 나열하는 방법은 제공되지 않습니다.

끔찍한 해킹은 system() 호출을 사용하고 결과를 구문 분석하는 것입니다.가장 합리적인 해결책은 다음과 같은 일종의 크로스 플랫폼 라이브러리를 사용하는 것입니다. Qt 또는 POSIX.

우리는 2019년입니다.우리는 파일 시스템 표준 라이브러리 C++.그만큼 Filesystem library 경로, 일반 파일 및 디렉터리와 같은 파일 시스템 및 해당 구성 요소에 대한 작업을 수행하기 위한 기능을 제공합니다.

에 중요한 메모가 있습니다. 이 링크 이식성 문제를 고려하고 있다면.그것은 말한다:

계층적 파일 시스템이 구현에 액세스할 수 없거나 필요한 기능을 제공하지 않는 경우 파일 시스템 라이브러리 기능을 사용하지 못할 수 있습니다.기본 파일 시스템에서 지원하지 않는 경우 일부 기능을 사용하지 못할 수 있습니다(예:FAT 파일 시스템에는 심볼릭 링크가 없으며 여러 하드링크를 금지합니다.이러한 경우 오류를 보고해야 합니다.

파일 시스템 라이브러리는 원래 다음과 같이 개발되었습니다. boost.filesystem, 는 기술 사양 ISO/IEC TS 18822:2015로 게시되었으며 최종적으로 C++17부터 ISO C++로 병합되었습니다.부스트 구현은 현재 C++17 라이브러리보다 더 많은 컴파일러와 플랫폼에서 사용할 수 있습니다.

@adi-shavit은 이 질문이 std::experimental의 일부였을 때 답변했으며 2017년에 이 답변을 업데이트했습니다.라이브러리에 대해 더 자세히 설명하고 더 자세한 예를 보여주고 싶습니다.

std::파일 시스템::recursive_directory_iterator 이다 LegacyInputIterator 이는 디렉토리의 Directory_entry 요소와 모든 하위 디렉토리의 항목을 반복적으로 반복합니다.각 디렉토리 항목이 한 번만 방문된다는 점을 제외하면 반복 순서는 지정되지 않습니다.

하위 디렉터리 항목을 재귀적으로 반복하지 않으려면 다음을 수행하십시오. 디렉토리_반복자 사용되어야한다.

두 반복자 모두 다음의 객체를 반환합니다. 디렉토리_항목. directory_entry 다음과 같은 다양한 유용한 멤버 기능이 있습니다. is_regular_file, is_directory, is_socket, is_symlink 등.그만큼 path() 멤버 함수는 다음의 객체를 반환합니다. 표준::파일 시스템::경로 그리고 그것은 얻는 데 사용될 수 있습니다 file extension, filename, root name.

아래 예를 고려하십시오.나는 사용해 왔다 Ubuntu 다음을 사용하여 터미널을 통해 컴파일했습니다.

g++ example.cpp --std=c++17 -lstdc++fs -Wall

#include <iostream>
#include <string>
#include <filesystem>

void listFiles(std::string path)
{
    for (auto& dirEntry: std::filesystem::recursive_directory_iterator(path)) {
        if (!dirEntry.is_regular_file()) {
            std::cout << "Directory: " << dirEntry.path() << std::endl;
            continue;
        }
        std::filesystem::path file = dirEntry.path();
        std::cout << "Filename: " << file.filename() << " extension: " << file.extension() << std::endl;

    }
}

int main()
{
    listFiles("./");
    return 0;
}

Windows를 사용하는 경우 FindFirstFile을 FindNextFile API와 함께 사용할 수 있습니다.FindFileData.dwFileAttributes를 사용하여 지정된 경로가 파일인지 디렉터리인지 확인할 수 있습니다.디렉터리인 경우 알고리즘을 재귀적으로 반복할 수 있습니다.

여기에서는 Windows 시스템의 모든 파일을 나열하는 몇 가지 코드를 구성했습니다.

http://dreams-soft.com/projects/traverse-directory

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top