resueltos - ¿Cómo iteramos a través de cada archivo/directorio recursivamente en C++ estándar?
que es la herencia en c++ (14)
Además del sistema de archivos boost :: mencionado anteriormente, es posible que desee examinar wxWidgets::wxDir y Qt::QDir .
Tanto wxWidgets como Qt son frameworks C ++ de código abierto y plataforma cruzada.
wxDir
proporciona una forma flexible de recorrer archivos recursivamente utilizando Traverse()
o una función GetAllFiles()
más simple. Además, puede implementar el GetFirst()
con las GetFirst()
y GetNext()
(supongo que Traverse () y GetAllFiles () son envoltorios que finalmente usan las funciones GetFirst () y GetNext ()).
QDir
proporciona acceso a estructuras de directorios y sus contenidos. Hay varias formas de recorrer directorios con QDir. Puede iterar sobre el contenido del directorio (incluidos los subdirectorios) con QDirIterator instanciado con el indicador QDirIterator :: Subdirectories. Otra forma es usar la función GetEntryList () de QDir e implementar un recorrido recursivo.
Aquí hay un código de muestra (tomado de here # Ejemplo 8-5) que muestra cómo iterar sobre todos los subdirectorios.
#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;
}
¿Cómo iteramos a través de cada archivo / directorio recursivamente en C ++ estándar?
Boost :: filesystem proporciona recursive_directory_iterator, que es bastante conveniente para esta tarea:
#include "boost/filesystem.hpp"
#include <iostream>
boost::filesystem::recursive_directory_iterator end;
for (it("./"); it != end; ++it) {
std::cout << *it << std::endl;
}
En C ++ 11/14 con el "Sistema de archivos TS", el encabezado recursive_directory_iterator y el rango- simplemente puede hacer esto:
#include <experimental/filesystem>
using std::experimental::filesystem::recursive_directory_iterator;
...
for (auto& dirEntry : recursive_directory_iterator(myPath))
cout << dirEntry << endl;
En C ++ estándar, técnicamente no hay forma de hacerlo ya que el C ++ estándar no tiene una concepción de directorios. Si desea expandir su red un poco, le Boost.FileSystem utilizar Boost.FileSystem . Esto ha sido aceptado para su inclusión en TR2, por lo que le brinda la mejor oportunidad de mantener su implementación lo más cerca posible del estándar.
Un ejemplo, tomado directamente del sitio web:
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;
}
Es posible que desee examinar boost.filesystem
http://www.boost.org/doc/libs/1_31_0/libs/filesystem/doc/index.htm
Probablemente seas mejor con boost o con el sistema de archivos experimental de c ++ 14. SI está analizando un directorio interno (es decir, usado para que su programa almacene datos después de que se cerró el programa), cree un archivo de índice que tenga un índice del contenido del archivo. Por cierto, es probable que necesites usar boost en el futuro, así que si no lo tienes instalado, ¡instálalo! En segundo lugar, puede usar una compilación condicional:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
código en https://.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.
Puede usar ftw(3)
o nftw(3)
para recorrer una jerarquía de sistema de archivos en C o C ++ en sistemas POSIX .
Puedes hacerlo aún más simple con el nuevo rango de C++11 basado 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;
}
Si está en Windows, puede usar FindFirstFile junto con la API FindNextFile. Puede usar FindFileData.dwFileAttributes para verificar si una ruta determinada es un archivo o un directorio. Si es un directorio, puede repetir el algoritmo recursivamente.
Aquí, he reunido un código que enumera todos los archivos en una máquina con Windows.
Si usa la API de Win32, puede usar las funciones FindFirstFile y FindNextFile .
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
Para el recorrido recursivo de directorios, debe inspeccionar cada WIN32_FIND_DATA.dwFileAttributes para verificar si el bit FILE_ATTRIBUTE_DIRECTORY está establecido. Si el bit está configurado, puede llamar recurrentemente a la función con ese directorio. Alternativamente, puede usar una pila para proporcionar el mismo efecto de una llamada recursiva pero evitando el desbordamiento de pila para árboles de ruta muy largos.
#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;
}
Tu no El estándar C ++ no expone al concepto de un directorio. Específicamente, no proporciona ninguna forma de listar todos los archivos en un directorio.
Un hack horrible sería usar llamadas al sistema () y analizar los resultados. La solución más razonable sería usar algún tipo de biblioteca multiplataforma como Qt o incluso POSIX .
Tu no El estándar C ++ no tiene ningún concepto de directorios. Depende de la implementación convertir una cadena en un manejador de archivo. El contenido de esa cadena y de lo que se asigna depende del sistema operativo. Tenga en cuenta que C ++ se puede usar para escribir ese SO, por lo que se usa en un nivel en el que todavía no se ha preguntado cómo iterar a través de un directorio (porque está escribiendo el código de administración del directorio).
Mire la documentación de su API de sistema operativo para saber cómo hacer esto. Si necesita ser portátil, tendrá que tener un montón de #ifdef para varios sistemas operativos.
Una solución rápida es usar la biblioteca Dirent.h de Dirent.h
Fragmento de código de trabajo de 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;
}
readdir()
llamar a funciones específicas del sistema operativo para el recorrido del sistema de archivos, como open()
y readdir()
. El estándar C no especifica ninguna función relacionada con el sistema de archivos.