표준 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를 사용하는 경우 FindFirstFile 및 FindNextFile 함수를 사용할 수 있습니다 .
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
및 Boost를 사용하면 더 간단하게 만들 수 있습니다 .
#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 :: wxDir 및 Qt :: QDir 을 검사 할 수 있습니다 .
wxWidget과 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;
}