¿Cómo iterar a través de cada archivo/directorio recursivamente en C++ estándar?¿Cómo iterar a través de cada archivo/directorio recursivamente en C++ estándar?
Respuesta
En C++ estándar, técnicamente no hay manera de hacer esto desde el estándar de C++ no tiene concepción de directorios. Si desea expandir su red un poco, le recomendamos que consulte 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 de la página 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;
}
C++ no tiene concepto de archivos? ¿Qué pasa con std :: fstream? ¿O fopen? – Kevin
archivos, no directorios –
Actualización con respecto a la última versión de boost: en caso de que alguien se tropiece con esta respuesta, el último impulso incluye una conveniencia class boost :: recursive_directory_iterator por lo que ya no es necesario escribir el ciclo anterior con llamada recursiva explícita. Enlace: http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/reference.html#Class-recursive_directory_iterator – JasDev
Debe 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.
¿Qué pasa con C++? ¿Hay alguna de esas funciones en iostream? –
Solo para archivos. No hay ningún tipo de funciones de "mostrarme todos los archivos en un directorio". –
@ 1800: los directorios son archivos. –
Es posible que desee examinar boost.filesystem
http://www.boost.org/doc/libs/1_31_0/libs/filesystem/doc/index.htm
Usted no lo hace. 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 las 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.
Si se utiliza la API de Win32 puede utilizar el FindFirstFile y FindNextFile funciones.
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
Para recorrido recursivo de directorios que debe inspeccionar cada WIN32_FIND_DATA.dwFileAttributes para comprobar si se establece el bit FILE_ATTRIBUTE_DIRECTORY. 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;
}
¿cuánto tiempo te tomó escribir eso? Creo que tomaría menos tiempo pegar C++ a python y hacerlo en una línea. –
Esta es una buena solución no recursiva (¡que a veces es útil!). –
Por cierto, si alguien quiere editar el programa ligeramente para aceptar un parámetro de línea de comandos argv [1] para la ruta en lugar de uno codificado ("F: \\ cvsrepos"), la firma para main (int, char) sería cambie a wmain (int, wchar_t) de la siguiente manera: int wmain (int argc, wchar_t * argv []) – JasDev
Usted no lo hace. 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).
Consulte la documentación de su API de sistema operativo para saber cómo hacerlo. Si necesita ser portátil, tendrá que tener un grupo de #ifdef para varios sistemas operativos.
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 más simple GetAllFiles()
.También puede implementar el recorrido con las funciones 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í está el 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;
}
Doxygen utiliza QT como capa de compatibilidad de sistema operativo. Las herramientas básicas no usan una GUI en absoluto, solo el material del directorio (y otros componentes). –
una solución rápida está utilizando la biblioteca de C Dirent.h.
Trabajando fragmento de código 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;
}
Esta rutina no es recursiva. – user501138
Nota: no funciona en VC++. –
@TimCooper, por supuesto que no, dirent es posix específico. – Vorac
Usted puede hacer que sea aún más sencillo con la nueva gama C++11 basado for
y 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;
}
Usted puede utilizar ftw(3)
or nftw(3)
que caminar una jerarquía de sistema de archivos en C o C++ en los sistemas POSIX.
https://github.com/six-k/dtreetrawl/blob/f7c1d320225ee754b96fef28bb0774a2c34b91b8/dtreetrawl.c#L473 tiene un ejemplo de esto. El código hace algunas cosas más, pero actúa como un buen tutorial para el uso de 'nftw()'. –
Boost :: sistema de archivos proporciona recursive_directory_iterator, que es muy 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;
}
Si está en Windows, puede utilizar la API de FindFirstFile junto con 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 algunos códigos que enumeran todos los archivos en una máquina con Windows.
En C++ 11/14 con el "sistema de archivos TS", la cabecera <experimental/filesystem>
y gama- for
puede simplemente hacer esto:
#include <experimental/filesystem>
using std::experimental::filesystem::recursive_directory_iterator;
...
for (auto& dirEntry : recursive_directory_iterator(myPath))
cout << dirEntry << endl;
Evite el uso de 'using', use' namespace' en su lugar. –
¿Y por qué es eso? Mejor más específico que traer cosas que no usas. –
Revise mi edición, por favor, también agregué el espacio de nombre faltante. –
Probablemente sería mejor, ya sea con boost o cosas del sistema de archivos experimental de C++ 14. IF está analizando un directorio interno (es decir, utilizado para que su programa almacene datos después de que se cerró el programa), luego 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, se puede utilizar una compilación condicional:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
código al 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.
- 1. Iterar a través de la cola estándar
- 2. Perl iterar a través de cada coincidencia
- 3. Iterar a través de cada archivo en un directorio
- 4. Iterar a través de cada dígito en un número
- 5. Iterar a través de una matriz C
- 6. ¿Cómo iterar archivos recursivamente en Groovy?
- 7. Iterar a través de DataSet
- 8. Iterar a través de cada "coincidencia" (Ruby regex)
- 9. cómo iterar a través de las propiedades internas en C#
- 10. C# ¿Cómo puedo iterar a través del registro?
- 11. Cómo iterar a través de SAFEARRAY **
- 12. Cómo iterar a través de una cadena
- 13. Cómo iterar a través de un fd_set
- 14. Cómo iterar a través de una DataTable
- 15. ¿Cómo puedo iterar a través de cada elemento en una matriz n-dimensional en MATLAB?
- 16. ¿Cómo puedo iterar a través de elementos de QListWidget y trabajar con cada elemento?
- 17. ¿Cómo puedo iterar a través de cada píxel en una imagen .gif?
- 18. ¿Cómo puedo iterar a través de elementos DOM en PHP?
- 19. ¿Cómo puedo iterar a través de una cadena en Python?
- 20. Iterar a través fechas en SQL
- 21. Iterar a través de una tabla Lua de C++?
- 22. ¿Cómo iterar a través de una cadena y verificar el valor de bytes de cada carácter?
- 23. Iterar a través de una matriz de 2 dimensiones C#
- 24. ¿Cómo iterar a través de cada propiedad de un objeto vb.net personalizado?
- 25. Iterar a través de 2 listas
- 26. forma orientada a objetos para iterar a través de un estándar :: vector?
- 27. ¿Cómo iterar a través de hash (de Hashes) en Perl?
- 28. Cómo iterar a través de los elementos de una vista
- 29. Iterar a través de NSData bytes
- 30. Iteración a través de contenedores estándar en openmp
No estándar de C++: http://pocoproject.org/docs/Poco.DirectoryIterator.html –
Esto pronto se debe estar en el estándar a través de [Filesystem TS] (http://en.cppreference.com/w/cpp/experimental/fs), con [recursive_directory_iterator] (http: //en.cppreference.com/w/cpp/experimental/fs/recursive_directory_iterator) –
Si el uso de una biblioteca C estándar no interfiere en llamar a un programa C++ como 'estándar', [nftw()] (https: //linux.die .net/man/3/nftw). Aquí hay un [ejemplo] práctico (https://github.com/six-k/dtreetrawl/blob/f7c1d320225ee754b96fef28bb0774a2c34b91b8/dtreetrawl.c#L473) –