표준 C++에서 모든 파일/디렉토리를 어떻게 반복적으로 반복합니까?
-
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 표준은 파일 시스템 관련 기능을 지정하지 않습니다.
우리는 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 시스템의 모든 파일을 나열하는 몇 가지 코드를 구성했습니다.