표준 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;
}
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 ++ 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>
헤더 에서 찾을 수 있습니다 (더 이상 "실험용"이 아님).
새로운 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;
}
POSIX 시스템의 C 또는 C ++에서 ftw(3)
또는nftw(3)
을 사용 하여 파일 시스템 계층 구조를 살펴볼 수 있습니다.
You would probably be best with either boost or c++14's experimental filesystem stuff. IF you are parsing an internal directory (ie. used for your program to store data after the program was closed), then make an index file that has an index of the file contents. By the way, you probably would need to use boost in the future, so if you don't have it installed, install it! Second of all, you could use a conditional compilation, e.g.:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif
The code for each case is taken from 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.
You don't. The C++ standard has no concept of directories. It is up to the implementation to turn a string into a file handle. The contents of that string and what it maps to is OS dependent. Keep in mind that C++ can be used to write that OS, so it gets used at a level where asking how to iterate through a directory is not yet defined (because you are writing the directory management code).
Look at your OS API documentation for how to do this. If you need to be portable, you will have to have a bunch of #ifdefs for various OSes.
You need to call OS-specific functions for filesystem traversal, like open()
and readdir()
. The C standard does not specify any filesystem-related functions.
You don't. Standard C++ doesn't expose to concept of a directory. Specifically it doesn't give any way to list all the files in a directory.
A horrible hack would be to use system() calls and to parse the results. The most reasonable solution would be to use some kind of cross-platform library such as Qt or even POSIX.
We are in 2019. We have filesystem standard library in C++
. The Filesystem library
provides facilities for performing operations on file systems and their components, such as paths, regular files, and directories.
There is an important note on this link if you are considering portability issues. It says:
The filesystem library facilities may be unavailable if a hierarchical file system is not accessible to the implementation, or if it does not provide the necessary capabilities. Some features may not be available if they are not supported by the underlying file system (e.g. the FAT filesystem lacks symbolic links and forbids multiple hardlinks). In those cases, errors must be reported.
The filesystem library was originally developed as boost.filesystem
, was published as the technical specification ISO/IEC TS 18822:2015, and finally merged to ISO C++ as of C++17. The boost implementation is currently available on more compilers and platforms than the C++17 library.
@adi-shavit has answered this question when it was part of std::experimental and he has updated this answer in 2017. I want to give more details about the library and show more detailed example.
std::filesystem::recursive_directory_iterator is an LegacyInputIterator
that iterates over the directory_entry elements of a directory, and, recursively, over the entries of all subdirectories. The iteration order is unspecified, except that each directory entry is visited only once.
If you don't want to recursively iterate over the entries of subdirectories, then directory_iterator should be used.
Both iterators returns an object of directory_entry. directory_entry
has various useful member functions like is_regular_file
, is_directory
, is_socket
, is_symlink
etc. The path()
member function returns an object of std::filesystem::path and it can be used to get file extension
, filename
, root name
.
Consider the example below. I have been using Ubuntu
and compiled it over the terminal using
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;
}
If you are on Windows, you can use the FindFirstFile together with FindNextFile API. You can use FindFileData.dwFileAttributes to check if a given path is a file or a directory. If it's a directory, you can recursively repeat the algorithm.
Here, I have put together some code that lists all the files on a Windows machine.
'Programming' 카테고리의 다른 글
프로덕션에서 Rails 콘솔 실행 (0) | 2020.08.15 |
---|---|
문자열에서 숫자를 추출하고 정수 배열을 얻는 방법은 무엇입니까? (0) | 2020.08.15 |
jquery를 사용하지 않고 문서 높이와 너비를 얻는 방법 (0) | 2020.08.15 |
jquery를 사용하지 않고 문서 높이와 너비를 얻는 방법 (0) | 2020.08.15 |
div 너비보다 작은 테두리 길이? (0) | 2020.08.15 |