Porting QDirIterator to QDirListing | Qt Core | Qt 6.10.3

- Qt 6.10
- Qt Core
- Porting QDirIterator to QDirListing
- Qt 6.10.3 Reference Documentation

Comparison types overview ◦ Upgrading from Qt 5

# Porting QDirIterator to QDirListing

In Qt 6.8 QDirListing was added as a more efficient replacement for QDirIterator (the latter is still available for now). This page highlights some points to keep in mind when porting QDirIterator to QDirListing.

With QDirIterator you can control which entries are listed using flags from two separate enumerators, QDirIterator::IteratorFlags and QDir::Filters, whereas QDirListing has one set of flags to handle this task.

Porting QDirIterator::IteratorFlags to QDirListing::IteratorFlags is straightforward:

- QDirListing::IteratorFlag::Default is equivalent to QDirIterator::NoIteratorFlags
- QDirListing::IteratorFlag::FollowDirSymlinks is equivalent to QDirIterator::FollowSymlinks
- QDirListing::IteratorFlag::Recursive is equivalent to QDirIterator::Subdirectories

Porting QDir::Filters to QDirListing::IteratorFlags may be more complex, depending on the bitwise OR-ed combination of QDir::Filters you use.

- By default, QDirListing lists directories, regular files, symbolic links, and special (other) file system entries; you can exclude entries based on their type by using the various QDirListing::IteratorFlag::Exclude* flags.
- QDir's default filter is QDir::AllEntries, which is equivalent to:

       using F = QDirListing::IteratorFlag;
       QDirListing::IteratorFlags(F::ExcludeOther|F::ResolveSymlinks|F::IncludeDotAndDotDot);

- By default, QDirListing lists (Windows) drives, hence there is no equivalent for QDir::Drives.
- QDir::Readable, QDir::Writable, QDir::Executable, and QDir::AllDirs: The are no equivalent flags in QDirListing. If you need this functionality, iterate over the entries with a range-for loop and filter as required.

       QDirIterator dit(dirPath, QDir::AllEntries | QDir::Readable | QDir::Executable | QDir::NoDotAndDotDot);
       while (dit.hasNext()) {
           const QFileInfo fi = dit.nextFileInfo();
           fileNames.append(fi.fileName());
           ...
       }

       using F = QDirListing::IteratorFlags;
       for (const auto &dirEntry : QDirListing(dirPath, F::Default)) {
           const QFileInfo fi = dirEntry.fileInfo();
           // Filter based on readable and executable bits
           if (fi.isReadable() && fi.isExecutable()) {
               fileNames.append(dirEntry.fileName());
               ...
           }
       }

       // QDir::AllDirs causes dirs to always be listed regardless of `nameFilters`;
       // for example, to list ".so" files in a file dialog and still list all dirs:
       QDirIterator dit(dirPath, nameFilters, QDir::AllDirs | QDir::NoDotAndDotDot);
       while (dit.hasNext()) {
           const QFileInfo fi = dit.nextFileInfo();
           ...
       }

       // Equivalent code using QDirListing:
       using F = QDirListing::IteratorFlags;
       for (const auto &dirEntry : QDirListing(dirPath, F::Default)) {
           const QFileInfo fi = dirEntry.fileInfo();
           if (fi.isDir() || fi.fileName().endsWith(".so"_L1)) {
               ...
           }
       }

- With QDirListing the semantics of QDir::NoDot, QDir::NoDotDot and QDir::NoDotAndDotDot have been combined into one flag. By default, QDirListing doesn't list the special entries `.` and `..`. Set QDirListing::IteratorFlag::IncludeDotAndDotDot to list them.

## Symbolic Links

By default, QDirIterator resolves symbolic links unless QDir::NoSymlinks is set, whereas QDirListing doesn't resolve symbolic links unless QDirListing::IteratorFlag::ResolveSymlinks is set, in which case the filtering is done based on the type of the target of the symbolic link, not the symbolic link itself. For example, to list only regular files and symbolic links to regular files, you must set QDirListing::IteratorFlag::FilesOnly and QDirListing::IteratorFlag::ResolveSymlinks.

     // Symbolic links are resolved by default
     QDirIterator dit(dirPath, QDir::Files | QDir::NoDotAndDotDot);
     while (dit.hasNext()) {
         const QFileInfo fi = dit.nextFileInfo();
         fileNames.append(fi.fileName());
         ...
     }

     // To preserve the behavior of the code above, set ResolveSymlinks:
     using F = QDirListing::IteratorFlags;
     for (const auto &dirEntry : QDirListing(dirPath, F::FilesOnly | F::ResolveSymlinks)) {
         fileNames.append(dirEntry.fileName());
         ...
     }

## QDirListing::DirEntry

QDirListing::DirEntry offers a subset of QFileInfo's API (for example, fileName(), filePath(), exists()). The main advantage of DirEntry's API is delaying the (rather expensive) `stat()` or `lstat()` calls if we already got the needed info by some other means. On Linux, for example, internally we use readdir() to iterate over a directory tree, and we get the name and type of the entry as part of the returned info. So if all you want is the file name use, QDirListing::DirEntry::fileName() instead of QDirListing::DirEntry::fileInfo().fileName() (QDirListing will construct a QFileInfo internally and use that transparently when needed).

Comparison types overview ◦ Upgrading from Qt 5