Recursivamente iterar sobre todos los archivos en un directorio y sus subdirectorios en Qt

Quiero escanear de forma recursiva un directorio y todos sus subdirectorios en busca de archivos con una extensión determinada, por ejemplo, todos los archivos * .jpg. ¿Cómo puedes hacer eso en Qt?

preguntado el 08 de noviembre de 11 a las 15:11

Además, Qt tiene un objeto QFileSystemModel que puede considerar examinar:

4 Respuestas

Te sugiero que eches un vistazo QDirIterator.

QDirIterator it(dir, QStringList() << "*.jpg", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext())
    qDebug() << it.next();

Simplemente podrías usar QDir :: entryList () recursivamente, pero QDirIterator es más simple. Además, si tiene directorios con una gran cantidad de archivos, obtendrá listas bastante grandes de QDir :: entryList (), lo que puede no ser bueno en pequeños dispositivos integrados.

Ejemplo (dir es QDir :: currentPath ()):

luca @ ~/it_test - [] $ tree
.
├── dir1
│   ├── image2.jpg
│   └── image3.jpg
├── dir2
│   └── image4.png
├── dir3
│   └── image5.jpg
└── image1.jpg

3 directories, 5 files
luca @ ~/it_test - [] $ /path/to/app
"/home/luca/it_test/image1.jpg"
"/home/luca/it_test/dir3/image5.jpg"
"/home/luca/it_test/dir1/image2.jpg"
"/home/luca/it_test/dir1/image3.jpg"

Respondido el 26 de Septiembre de 21 a las 23:09

Perdí mucho tiempo por no leer correctamente los documentos oficiales. Tenga en cuenta "Después de la construcción, el iterador se encuentra antes de la primera entrada de directorio. next() La función devuelve la ruta a la siguiente entrada del directorio y avanza el iterador ". Por lo tanto, su código que trata con archivos debe ir después it.next(). - Andrew-Dufresne

Veo este bloque de código por todas partes, pero no funciona. Encuentra todos los archivos que coinciden con el patrón global solo en el nivel superior del árbol de directorios y no desciende a niveles inferiores. - Seis grados

@SixDegrees no estoy seguro de lo que quieres decir. Agregué un ejemplo. - Luca Carlon

Esto debería funcionar :

void scanDir(QDir dir)
{
    dir.setNameFilters(QStringList("*.nut"));
    dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);

    qDebug() << "Scanning: " << dir.path();

    QStringList fileList = dir.entryList();
    for (int i=0; i<fileList.count(); i++)
    {
        if(fileList[i] != "main.nut" &&
           fileList[i] != "info.nut")
        {
            qDebug() << "Found file: " << fileList[i];
        }
    }

    dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
    QStringList dirList = dir.entryList();
    for (int i=0; i<dirList.size(); ++i)
    {
        QString newPath = QString("%1/%2").arg(dir.absolutePath()).arg(dirList.at(i));
        scanDir(QDir(newPath));
    }
}

Las diferencias con su código son las siguientes:

  • Amplitud de la primera búsqueda en lugar de la profundidad de la primera búsqueda (no hay razón para ello, solo lo prefiero)
  • Más filtros para evitar enlaces simbólicos
  • EntryList en lugar de EntryInfoList. No es necesario si solo desea el nombre del archivo.

Lo probé y funciona correctamente, pero observe lo siguiente:

  • Esto puede llevar mucho tiempo, así que considere ejecutarlo desde el hilo.
  • Si hay una recursión profunda, es posible que tenga problemas con su pila

respondido 08 nov., 11:20

A menos que me esté perdiendo algo, cambió la salida de su función. Quiere la lista de todos los archivos en el directorio dado, mientras que su función solo imprimirá los nombres de los archivos pero no proporcionará la lista. - laurent

No estaba llenando el nutFiles lista de cadenas, por lo que no incluí esta parte. Sin embargo, es bastante fácil modificar la función y obtener la lista de todos los archivos. pnezis

Usé QDirIterator.

Así es como lo hago y lo simple que fue encontrar todas las rutas de archivo XML absolutas de forma recursiva muy rápido (Qt4.8.1):

// used to store the file paths
filesStack = new QStack<QString>();

// I use a file dialog to let the user choose the root folder to search in
if (fileDialog->exec() == QFileDialog::Accepted) {
    QDir selectedDir(fileDialog->selectedFiles().first());
    selectedDir.setFilter(QDir::Files |
                          QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
    QStringList qsl; qsl.append("*.xml"); // I only want XML files
    selectedDir.setNameFilters(qsl);
    findFilesRecursively(selectedDir);
}

// this function stores the absolute paths of each file in a QVector
void findFilesRecursively(QDir rootDir) {
    QDirIterator it(rootDir, QDirIterator::Subdirectories);
    while(it.hasNext()) {
        filesStack->push(it.next());
    }
}

Gracias a todos por las pistas.

EDITAR: Es posible que haya omitido algunas declaraciones, cuidado.

Respondido el 29 de enero de 13 a las 22:01

Otra muestra que indexa todos los archivos, usando QFileInfo:

void ID3Tab::scanDir( QDir dir )
{ QFileInfoList fil = dir.entryInfoList( QStringList( "*.mp3" ),
                                         QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks,
                                         QDir::Name | QDir::IgnoreCase );
  foreach ( QFileInfo fi, fil )
    indexFile( fi );

  QFileInfoList dil = dir.entryInfoList( QStringList( "*" ),
                                         QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks,
                                         QDir::Name | QDir::IgnoreCase );
  foreach ( QFileInfo di, dil )
    scanDir( QDir( di.absoluteFilePath() ) );
}

respondido 15 mar '20, 18:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.