Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdirlisting.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5/*!
6 \since 6.8
7 \class QDirListing
8 \inmodule QtCore
9 \ingroup io
10 \brief The QDirListing class provides an STL-style iterator for directory entries.
11
12 You can use QDirListing to navigate entries of a directory one at a time.
13 It is similar to QDir::entryList() and QDir::entryInfoList(), but because
14 it lists entries one at a time instead of all at once, it scales better
15 and is more suitable for large directories. It also supports listing
16 directory contents recursively, and following symbolic links. Unlike
17 QDir::entryList(), QDirListing does not support sorting.
18
19 The QDirListing constructor takes a directory path string as
20 argument. Here's how to iterate over all entries recursively:
21
22 \snippet code/src_corelib_io_qdirlisting.cpp 0
23
24 Here's how to find and read all regular files filtered by name, recursively:
25
26 \snippet code/src_corelib_io_qdirlisting.cpp 1
27
28 Here's how to list only regular files, recursively:
29 \snippet code/src_corelib_io_qdirlisting.cpp 5
30
31 Here's how to list only regular files and symbolic links to regular
32 files, recursively:
33 \snippet code/src_corelib_io_qdirlisting.cpp 6
34
35//! [std-input-iterator-tag]
36 QDirListing::const_iterator models C++20
37 \l{https://en.cppreference.com/w/cpp/iterator/input_iterator}{std::input_iterator},
38 that is, it is a move-only, forward-only, single-pass iterator, that
39 doesn't allow random access.
40//! [std-input-iterator-tag]
41 It can be used in ranged-for loops (or with C++20 range algorithms that don't
42 require random access iterators). Dereferencing a valid iterator returns
43 a QDirListing::DirEntry object. The (c)end() sentinel marks the end of
44 the iteration. Dereferencing an iterator that is equal to \l{sentinel} is
45 undefined behavior.
46
47 QDirListing::DirEntry offers a subset of QFileInfo's API (for example,
48 fileName(), filePath(), exists()). Internally, DirEntry only constructs
49 a QFileInfo object if needed, that is, if the info hasn't been already
50 fetched by other system functions. You can use DirEntry::fileInfo()
51 to get a QFileInfo. For example:
52
53 \snippet code/src_corelib_io_qdirlisting.cpp 3
54 \snippet code/src_corelib_io_qdirlisting.cpp 4
55
56 \sa QDir, QDir::entryList()
57*/
58
59/*! \enum QDirListing::IteratorFlag
60
61 This enum class describes flags that can be used to configure the behavior
62 of QDirListing. Values from this enumerator can be bitwise OR'ed together.
63
64 \value Default
65 List all files, directories and symbolic links, including broken
66 symlinks (where the target doesn't exist).
67 Hidden files and directories and the special entries \c{.} and \c{..}
68 aren't listed by default.
69
70 \value ExcludeFiles
71 Don't list regular files. When combined with ResolveSymlinks, symbolic
72 links to regular files will be excluded too.
73
74 \value ExcludeDirs
75 Don't list directories. When combined with ResolveSymlinks, symbolic
76 links to directories will be excluded too.
77
78 \value ExcludeSpecial
79 Don't list special system files:
80 \list
81 \li On Unix: an entry that is not a directory, regular file or
82 symbolic link (including broken symlinks). That is, FIFO,
83 socket, character device, or block device.
84 \li On Windows: \c {.lnk}.
85 \endlist
86
87 \value ResolveSymlinks
88 Filter symbolic links based on the type of the target of the link,
89 rather than the symbolic link itself. With this flag, broken symbolic
90 links (where the target doesn't exist) are excluded. This flag is
91 ignored on operating systems that don't support symbolic links.
92
93 \value FilesOnly
94 Only regular files will be listed. When combined with ResolveSymlinks,
95 symbolic links to files will also be listed.
96
97 \value DirsOnly
98 Only directories will be listed. When combined with ResolveSymlinks,
99 symbolic links to directories will also be listed.
100
101 \value IncludeHidden
102 List hidden entries. When combined with Recursive, the iteration will
103 recurse into hidden sub-directories as well.
104
105 \value IncludeDotAndDotDot
106 List the \c {.} and \c{..} special entries.
107
108 \value CaseSensitive
109 The file glob patterns in the name filters passed to the QDirListing
110 constructor, will be matched case sensitively (for details, see
111 QDir::setNameFilters()).
112
113 \value Recursive
114 List entries inside all sub-directories as well. When combined with
115 FollowDirSymlinks, symbolic links to directories will be iterated too.
116
117 \value FollowDirSymlinks
118 When combined with Recursive, symbolic links to directories will be
119 iterated too. Symbolic link loops (e.g., link => . or link => ..) are
120 automatically detected and ignored.
121*/
122
123#include "qdirlisting.h"
124#include "qdirentryinfo_p.h"
125
126#include "qdir_p.h"
127#include "qdiriterator.h"
129
130#if QT_CONFIG(regularexpression)
131#include <QtCore/qregularexpression.h>
132#endif
133
134#include <QtCore/private/qfilesystemiterator_p.h>
135#include <QtCore/private/qfilesystementry_p.h>
136#include <QtCore/private/qfilesystemmetadata_p.h>
137#include <QtCore/private/qfilesystemengine_p.h>
138#include <QtCore/private/qfileinfo_p.h>
139#include <QtCore/private/qduplicatetracker_p.h>
140
141#include <memory>
142#include <vector>
143
144QT_BEGIN_NAMESPACE
145
146using namespace Qt::StringLiterals;
147
148static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags)
149{
150 using F = QDirListing::IteratorFlag;
151 QDirListing::IteratorFlags listerFlags;
152
153 if (flags & QDirIterator::NoIteratorFlags)
154 listerFlags.setFlag(F::Default);
155 if (flags & QDirIterator::FollowSymlinks)
156 listerFlags.setFlag(F::FollowDirSymlinks);
157 if (flags & QDirIterator::Subdirectories)
158 listerFlags.setFlag(F::Recursive);
159
160 return listerFlags;
161}
162
164{
165public:
166 void init(bool resolveEngine);
167 void advance();
169
170 bool entryMatches(QDirEntryInfo &info);
171 void pushDirectory(QDirEntryInfo &info);
173
174 void checkAndPushDirectory(QDirEntryInfo &info);
175 bool matchesFilters(QDirEntryInfo &data) const;
176 bool hasIterators() const;
177
178 bool matchesLegacyFilters(QDirEntryInfo &data) const;
179 void setLegacyFilters(QDir::Filters dirFilters, QDirIterator::IteratorFlags dirIteratorFlags)
180 {
181 useLegacyFilters = true;
182 legacyDirFilters = dirFilters;
183 iteratorFlags = toDirListingFlags(dirIteratorFlags);
184 }
185
191
192 bool useLegacyFilters = false;
194
195#if QT_CONFIG(regularexpression)
197 bool regexMatchesName(const QString &fileName) const
198 {
199 if (nameRegExps.isEmpty())
200 return true;
201 auto hasMatch = [&fileName](const auto &re) { return re.match(fileName).hasMatch(); };
203 }
204#endif
205
208#ifndef QT_NO_FILESYSTEMITERATOR
211#endif
212
213 // Loop protection
215};
216
217void QDirListingPrivate::init(bool resolveEngine = true)
218{
219 if (nameFilters.contains("*"_L1))
220 nameFilters.clear();
221
222 if (useLegacyFilters) {
223 if (legacyDirFilters == QDir::NoFilter)
224 legacyDirFilters = QDir::AllEntries;
225 }
226
227#if QT_CONFIG(regularexpression)
228 nameRegExps.reserve(nameFilters.size());
229
230 const bool isCase = [this] {
231 if (useLegacyFilters)
232 return legacyDirFilters.testAnyFlags(QDir::CaseSensitive);
233 return iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::CaseSensitive);
234 }();
235
236 const auto cs = isCase ? Qt::CaseSensitive : Qt::CaseInsensitive;
237 for (const auto &filter : nameFilters)
238 nameRegExps.emplace_back(QRegularExpression::fromWildcard(filter, cs));
239#endif
240
241 if (resolveEngine) {
242 engine = QFileSystemEngine::createLegacyEngine(initialEntryInfo.entry,
243 initialEntryInfo.metaData);
244 }
245}
246
247/*!
248 \internal
249
250 Resets the iteration state (if any), so that calling begin()/cbegin()
251 always starts iterating anew.
252*/
254{
255#ifndef QT_NO_FILESYSTEMITERATOR
256 nativeIterators.clear();
257#endif
258 fileEngineIterators.clear();
259 visitedLinks.clear();
260 pushDirectory(initialEntryInfo);
261}
262
263void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo)
264{
265 const QString path = [&entryInfo] {
266#ifdef Q_OS_WIN
267 if (entryInfo.isSymLink())
268 return entryInfo.canonicalFilePath();
269#endif
270 return entryInfo.filePath();
271 }();
272
273
274 if (iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowDirSymlinks)) {
275 // Stop link loops
276 if (visitedLinks.hasSeen(entryInfo.canonicalFilePath()))
277 return;
278 }
279
280 if (engine) {
281 engine->setFileName(path);
282 if (auto it = engine->beginEntryList(path, iteratorFlags, nameFilters)) {
283 fileEngineIterators.emplace_back(std::move(it));
284 } else {
285 // No iterator; no entry list.
286 }
287 } else {
288#ifndef QT_NO_FILESYSTEMITERATOR
289 QFileSystemEntry *fentry = nullptr;
290 if (entryInfo.fileInfoOpt)
291 fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry;
292 else
293 fentry = &entryInfo.entry;
294 nativeIterators.emplace_back(std::make_unique<QFileSystemIterator>(*fentry, iteratorFlags));
295#else
296 qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
297#endif
298 }
299}
300
301bool QDirListingPrivate::entryMatches(QDirEntryInfo &entryInfo)
302{
303 checkAndPushDirectory(entryInfo);
304 if (useLegacyFilters)
305 return matchesLegacyFilters(entryInfo);
306 return matchesFilters(entryInfo);
307}
308
309/*!
310 \internal
311
312 Advances the internal iterator, either a QAbstractFileEngineIterator (e.g.
313 QResourceFileEngineIterator) or a QFileSystemIterator (which uses low-level
314 system methods, e.g. readdir() on Unix). The iterators are stored in a
315 vector.
316
317 A typical example of doing recursive iteration:
318 - while iterating directory A we find a sub-dir B
319 - an iterator for B is added to the vector
320 - B's iterator is processed (vector.back()) first; then the loop
321 goes back to processing A's iterator
322*/
324{
325 // Use get() in both code paths below because the iterator returned by back()
326 // may be invalidated due to reallocation when appending new iterators in
327 // pushDirectory().
328
329 if (engine) {
330 while (!fileEngineIterators.empty()) {
331 // Find the next valid iterator that matches the filters.
332 QAbstractFileEngineIterator *it;
333 while (it = fileEngineIterators.back().get(), it->advance()) {
334 QDirEntryInfo entryInfo;
335 entryInfo.fileInfoOpt = it->currentFileInfo();
336 if (entryMatches(entryInfo)) {
337 currentEntryInfo = std::move(entryInfo);
338 return;
339 }
340 }
341
342 fileEngineIterators.pop_back();
343 }
344 } else {
345#ifndef QT_NO_FILESYSTEMITERATOR
346 QDirEntryInfo entryInfo;
347 while (!nativeIterators.empty()) {
348 // Find the next valid iterator that matches the filters.
349 QFileSystemIterator *it;
350 while (it = nativeIterators.back().get(),
351 it->advance(entryInfo.entry, entryInfo.metaData)) {
352 if (entryMatches(entryInfo)) {
353 currentEntryInfo = std::move(entryInfo);
354 return;
355 }
356 entryInfo = {};
357 }
358
359 nativeIterators.pop_back();
360 }
361#endif
362 }
363}
364
365static bool isDotOrDotDot(QStringView fileName)
366{
367 return fileName == "."_L1 || fileName == ".."_L1;
368}
369
370void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo)
371{
372 using F = QDirListing::IteratorFlag;
373 // If we're doing flat iteration, we're done.
374 if (!iteratorFlags.testAnyFlags(F::Recursive))
375 return;
376
377 // Follow symlinks only when asked
378 if (!iteratorFlags.testAnyFlags(F::FollowDirSymlinks) && entryInfo.isSymLink())
379 return;
380
381 // Never follow . and ..
382 if (isDotOrDotDot(entryInfo.fileName()))
383 return;
384
385 // No hidden directories unless requested
386 const bool includeHidden = [this]() {
387 if (useLegacyFilters)
388 return legacyDirFilters.testAnyFlags(QDir::AllDirs | QDir::Hidden);
389 return iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::IncludeHidden);
390 }();
391 if (!includeHidden && entryInfo.isHidden())
392 return;
393
394 // Never follow non-directory entries
395 if (!entryInfo.isDir())
396 return;
397
398 pushDirectory(entryInfo);
399}
400
401/*!
402 \internal
403
404 Works the same as matchesFilters() but for the old QDir::Filters.
405*/
406bool QDirListingPrivate::matchesLegacyFilters(QDirEntryInfo &entryInfo) const
407{
408 Q_ASSERT(useLegacyFilters);
409
410 const QString &fileName = entryInfo.fileName();
411 if (fileName.isEmpty())
412 return false;
413
414 auto &filters = legacyDirFilters;
415
416 // filter . and ..?
417 const bool dotOrDotDot = isDotOrDotDot(fileName);
418 const qsizetype fileNameSize = fileName.size();
419 if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
420 return false;
421 if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
422 return false;
423
424 // name filter
425#if QT_CONFIG(regularexpression)
426 // Pass all entries through name filters, except dirs if AllDirs is set
427 if (!(filters.testAnyFlags(QDir::AllDirs) && entryInfo.isDir())) {
428 if (!regexMatchesName(fileName))
429 return false;
430 }
431#endif
432 // skip symlinks
433 const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
434 const bool includeSystem = filters.testAnyFlag(QDir::System);
435 if (skipSymlinks && entryInfo.isSymLink()) {
436 // The only reason to save this file is if it is a broken link and we are requesting system files.
437 if (!includeSystem || entryInfo.exists())
438 return false;
439 }
440
441 // filter hidden
442 const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
443 if (!includeHidden && !dotOrDotDot && entryInfo.isHidden())
444 return false;
445
446 // filter system files
447 if (!includeSystem) {
448 if (!entryInfo.isFile() && !entryInfo.isDir() && !entryInfo.isSymLink())
449 return false;
450 if (entryInfo.isSymLink() && !entryInfo.exists())
451 return false;
452 }
453
454 // skip directories
455 const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
456 if (skipDirs && entryInfo.isDir())
457 return false;
458
459 // skip files
460 const bool skipFiles = !(filters & QDir::Files);
461 if (skipFiles && entryInfo.isFile())
462 // Basically we need a reason not to exclude this file otherwise we just eliminate it.
463 return false;
464
465 // filter permissions
466 const auto perms = filters & QDir::PermissionMask;
467 const bool filterPermissions = perms != 0 && perms != QDir::PermissionMask;
468 if (filterPermissions) {
469 const bool doWritable = filters.testAnyFlags(QDir::Writable);
470 const bool doExecutable = filters.testAnyFlags(QDir::Executable);
471 const bool doReadable = filters.testAnyFlags(QDir::Readable);
472 if ((doReadable && !entryInfo.isReadable())
473 || (doWritable && !entryInfo.isWritable())
474 || (doExecutable && !entryInfo.isExecutable())) {
475 return false;
476 }
477 }
478
479 return true;
480}
481
482/*!
483 \internal
484
485 This function returns \c true if the current entry matches the filters
486 (i.e., the current entry will be returned as part of the directory
487 iteration); otherwise, \c false is returned.
488*/
489bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const
490{
491 using F = QDirListing::IteratorFlag;
492
493 const QString &fileName = entryInfo.fileName();
494 if (fileName.isEmpty())
495 return false;
496
497 if (isDotOrDotDot(fileName)) // All done, other checks below don't matter in this case
498 return iteratorFlags.testAnyFlags(F::IncludeDotAndDotDot);
499
500 // name filter
501#if QT_CONFIG(regularexpression)
502 if (!regexMatchesName(fileName))
503 return false;
504#endif // QT_CONFIG(regularexpression)
505
506 if (!iteratorFlags.testAnyFlag(F::IncludeHidden) && entryInfo.isHidden())
507 return false;
508
509 if (entryInfo.isSymLink()) {
510 // With ResolveSymlinks, we look at the type of the link's target,
511 // and exclude broken symlinks (where the target doesn't exist).
512 if (iteratorFlags.testAnyFlag(F::ResolveSymlinks)) {
513 if (!entryInfo.exists())
514 return false;
515 } else if (iteratorFlags.testAnyFlags(F::FilesOnly)
516 || iteratorFlags.testAnyFlags(F::DirsOnly)) {
517 return false; // symlink is not a file or dir
518 }
519 }
520
521 if (iteratorFlags.testAnyFlag(F::ExcludeSpecial)
522 && !entryInfo.isFile() && !entryInfo.isDir() && !entryInfo.isSymLink()) {
523 return false;
524 }
525
526 if (iteratorFlags.testAnyFlags(F::ExcludeDirs) && entryInfo.isDir())
527 return false;
528
529 if (iteratorFlags.testAnyFlags(F::ExcludeFiles) && entryInfo.isFile())
530 return false;
531
532 return true;
533}
534
536{
537 if (engine)
538 return !fileEngineIterators.empty();
539
540#if !defined(QT_NO_FILESYSTEMITERATOR)
541 return !nativeIterators.empty();
542#endif
543
544 return false;
545}
546
547/*!
548 Constructs a QDirListing that can iterate over \a path.
549
550 You can pass options via \a flags to control how the directory should
551 be iterated.
552
553 By default, \a flags is IteratorFlag::Default.
554
555 \sa IteratorFlags
556*/
557QDirListing::QDirListing(const QString &path, IteratorFlags flags)
558 : d(new QDirListingPrivate)
559{
560 d->initialEntryInfo.entry = QFileSystemEntry(path);
561 d->iteratorFlags = flags;
562 d->init();
563}
564
565/*!
566 Constructs a QDirListing that can iterate over \a path.
567
568 You can pass options via \a flags to control how the directory should
569 be iterated. By default, \a flags is IteratorFlag::Default.
570
571 The listed entries will be filtered according to the file glob patterns
572 in \a nameFilters (see QDir::setNameFilters() for more details).
573
574 For example, the following iterator could be used to iterate over audio
575 files:
576
577 \snippet code/src_corelib_io_qdirlisting.cpp 2
578
579 \sa IteratorFlags, QDir::setNameFilters()
580*/
581QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, IteratorFlags flags)
582 : d(new QDirListingPrivate)
583{
584 d->initialEntryInfo.entry = QFileSystemEntry(path);
585 d->nameFilters = nameFilters;
586 d->iteratorFlags = flags;
587 d->init();
588}
589
590/*!
591 \internal
592
593 Only used by classes that still have to use QDir::Filters; for example,
594 QDir, such usage may be deprecated at some point.
595
596 \a qdirFilters is converted to QDir::Filters and \a qdirIteratorFlags is
597 converted to QDirIterator::IteratorFlags (qdirlisting.h can't include
598 qdir.h or qdiriterator.h) and used to control the filtering of the
599 dir entries.
600*/
601QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, uint qdirFilters,
602 uint qdirIteratorFlags)
603 : d(new QDirListingPrivate)
604{
605 d->initialEntryInfo.entry = QFileSystemEntry(path);
606 d->nameFilters = nameFilters;
607 d->setLegacyFilters(QDir::Filters::fromInt(qdirFilters),
608 QDirIterator::IteratorFlags::fromInt(qdirIteratorFlags));
609 d->init();
610}
611
612/*!
613 \fn QDirListing::QDirListing(QDirListing &&other)
614
615 Move constructor. Moves \a other into this QDirListing.
616
617//! [partially-formed]
618 \note The moved-from object \a other is placed in a partially-formed state,
619 in which the only valid operations are destruction and assignment of a new
620 value.
621//! [partially-formed]
622*/
623
624/*!
625 \fn QDirListing &QDirListing::operator=(QDirListing &&other)
626
627 Move-assigns \a other to this QDirListing.
628
629 \include qdirlisting.cpp partially-formed
630*/
631
632/*!
633 Destroys the QDirListing.
634*/
635QDirListing::~QDirListing()
636{
637 delete d;
638}
639
640/*!
641 Returns the directory path used to construct this QDirListing.
642*/
643QString QDirListing::iteratorPath() const
644{
645 return d->initialEntryInfo.filePath();
646}
647
648/*!
649 Returns the set of IteratorFlags used to construct this QDirListing.
650*/
651QDirListing::IteratorFlags QDirListing::iteratorFlags() const
652{
653 return d->iteratorFlags;
654}
655
656/*!
657 Returns the list of file name glob filters used to construct this
658 QDirListing.
659*/
660QStringList QDirListing::nameFilters() const
661{
662 return d->nameFilters;
663}
664
665/*!
666 \class QDirListing::const_iterator
667 \since 6.8
668 \inmodule QtCore
669 \ingroup io
670
671 The iterator type returned by QDirListing::cbegin().
672
673//! [dirlisting-iterator-behavior]
674 \list
675 \li This is a forward-only, single-pass iterator (you cannot iterate
676 directory entries in reverse order)
677 \li Can't be copied, only \c{std::move()}d.
678 \li \include qdirlisting.cpp post-increment-partially-formed
679 \li Doesn't allow random access
680 \li Can be used in ranged-for loops; or with C++20 std::ranges algorithms
681 that don't require random access iterators
682 \li Dereferencing a valid iterator returns a \c{const DirEntry &}
683 \li (c)end() returns a \l QDirListing::sentinel that signals the end of
684 the iteration. Dereferencing an iterator that compares equal to end()
685 is undefined behavior
686 \endlist
687//! [dirlisting-iterator-behavior]
688
689 \include qdirlisting.cpp ranges-algorithms-note
690
691 \sa QDirListing, QDirListing::sentinel, QDirListing::DirEntry
692*/
693
694/*!
695 \typealias QDirListing::const_iterator::reference
696
697 A typedef for \c {const QDirListing::DirEntry &}.
698*/
699
700/*!
701 \typealias QDirListing::const_iterator::pointer
702
703 A typedef for \c {const QDirListing::DirEntry *}.
704*/
705
706/*!
707 \class QDirListing::sentinel
708 \since 6.8
709 \inmodule QtCore
710 \ingroup io
711
712 \l QDirListing returns an object of this type to signal the end of
713 iteration. Dereferencing a \l QDirListing::const_iterator that is
714 equal to \c sentinel{} is undefined behavior.
715
716 \include qdirlisting.cpp ranges-algorithms-note
717
718 \sa QDirListing, QDirListing::const_iterator, QDirListing::DirEntry
719*/
720
721/*!
722 \fn QDirListing::const_iterator QDirListing::begin() const
723 \fn QDirListing::const_iterator QDirListing::cbegin() const
724 \fn QDirListing::sentinel QDirListing::end() const
725 \fn QDirListing::sentinel QDirListing::cend() const
726
727 (c)begin() returns a QDirListing::const_iterator that can be used to
728 iterate over directory entries.
729
730 \include qdirlisting.cpp dirlisting-iterator-behavior
731
732 \note Each time (c)begin() is called on the same QDirListing object,
733 the internal state is reset and the iteration starts anew.
734
735 (Some of the above restrictions are dictated by the underlying system
736 library functions' implementation).
737
738 For example:
739 \snippet code/src_corelib_io_qdirlisting.cpp 0
740
741 Here's how to find and read all files filtered by name, recursively:
742 \snippet code/src_corelib_io_qdirlisting.cpp 1
743
744//! [ranges-algorithms-note]
745 \note The "classical" STL algorithms don't support iterator/sentinel, so
746 you need to use C++20 std::ranges algorithms for QDirListing, or else a
747 3rd-party library that provides range-based algorithms in C++17.
748//! [ranges-algorithms-note]
749
750 \sa QDirListing::DirEntry
751*/
753{
755 const_iterator it{d};
756 ++it;
757 return it;
758}
759
760/*!
761 \fn const QDirListing::DirEntry &QDirListing::const_iterator::operator*() const
762
763 Returns a \c{const QDirListing::DirEntry &} of the directory entry this
764 iterator points to.
765*/
766
767/*!
768 \fn const QDirListing::DirEntry *QDirListing::const_iterator::operator->() const
769
770 Returns a \c{const QDirListing::DirEntry *} to the directory entry this
771 iterator points to.
772*/
773
774/*!
775 \fn QDirListing::const_iterator::operator++()
776
777 Pre-increment operator.
778 Advances the iterator and returns a reference to it.
779*/
780
781/*!
782 \fn void QDirListing::const_iterator::operator++(int)
783
784 Post-increment operator.
785
786 \include qdirlisting.cpp std-input-iterator-tag
787
788//! [post-increment-partially-formed]
789 The return value of post-increment on objects that model
790 \c std::input_iterator is partially-formed (a copy of an iterator that
791 has since been advanced), the only valid operations on such an object
792 are destruction and assignment of a new iterator. Therefore the
793 post-increment operator advances the iterator and returns \c void.
794//! [post-increment-partially-formed]
795*/
796
797/*!
798 \internal
799
800 Implements the actual advancing. Not a member function to avoid forcing
801 DirEntry objects (and therefore const_iterator ones) onto the stack.
802*/
803auto QDirListing::next(DirEntry dirEntry) -> DirEntry
804{
805 dirEntry.dirListPtr->advance();
806 if (!dirEntry.dirListPtr->hasIterators())
807 return {}; // All done, make `this` equal to the end() iterator
808 return dirEntry;
809}
810
811/*!
812 \class QDirListing::DirEntry
813 \inmodule QtCore
814 \ingroup io
815
816 Dereferencing a valid QDirListing::const_iterator returns a DirEntry
817 object.
818
819 DirEntry offers a subset of QFileInfo's API (for example, fileName(),
820 filePath(), exists()). Internally, DirEntry only constructs a QFileInfo
821 object if needed, that is, if the info hasn't been already fetched
822 by other system functions. You can use DirEntry::fileInfo() to get a
823 QFileInfo. For example:
824
825 \snippet code/src_corelib_io_qdirlisting.cpp 3
826
827 \snippet code/src_corelib_io_qdirlisting.cpp 4
828*/
829
830/*!
831 \fn QFileInfo QDirListing::DirEntry::fileInfo() const
832 \fn QString QDirListing::DirEntry::fileName() const
833 \fn QString QDirListing::DirEntry::baseName() const
834 \fn QString QDirListing::DirEntry::completeBaseName() const
835 \fn QString QDirListing::DirEntry::suffix() const
836 \fn QString QDirListing::DirEntry::bundleName() const
837 \fn QString QDirListing::DirEntry::completeSuffix() const
838 \fn QString QDirListing::DirEntry::filePath() const
839 \fn QString QDirListing::DirEntry::canonicalFilePath() const
840 \fn QString QDirListing::DirEntry::absoluteFilePath() const
841 \fn QString QDirListing::DirEntry::absolutePath() const
842 \fn bool QDirListing::DirEntry::isDir() const
843 \fn bool QDirListing::DirEntry::isFile() const
844 \fn bool QDirListing::DirEntry::isSymLink() const
845 \fn bool QDirListing::DirEntry::exists() const
846 \fn bool QDirListing::DirEntry::isHidden() const
847 \fn bool QDirListing::DirEntry::isReadable() const
848 \fn bool QDirListing::DirEntry::isWritable() const
849 \fn bool QDirListing::DirEntry::isExecutable() const
850 \fn qint64 QDirListing::DirEntry::size() const
851 \fn QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
852 \fn QDateTime QDirListing::DirEntry::birthTime(const QTimeZone &tz) const;
853 \fn QDateTime QDirListing::DirEntry::metadataChangeTime(const QTimeZone &tz) const;
854 \fn QDateTime QDirListing::DirEntry::lastModified(const QTimeZone &tz) const;
855 \fn QDateTime QDirListing::DirEntry::lastRead(const QTimeZone &tz) const;
856
857 See the QFileInfo methods with the same names.
858*/
859
860QFileInfo QDirListing::DirEntry::fileInfo() const
861{
862 return dirListPtr->currentEntryInfo.fileInfo();
863}
864
865QString QDirListing::DirEntry::fileName() const
866{
867 return dirListPtr->currentEntryInfo.fileName();
868}
869
870QString QDirListing::DirEntry::baseName() const
871{
872 return dirListPtr->currentEntryInfo.baseName();
873}
874
875QString QDirListing::DirEntry::completeBaseName() const
876{
877 return dirListPtr->currentEntryInfo.completeBaseName();
878}
879
880QString QDirListing::DirEntry::suffix() const
881{
882 return dirListPtr->currentEntryInfo.suffix();
883}
884
885QString QDirListing::DirEntry::bundleName() const
886{
887 return dirListPtr->currentEntryInfo.bundleName();
888}
889
890QString QDirListing::DirEntry::completeSuffix() const
891{
892 return dirListPtr->currentEntryInfo.completeSuffix();
893}
894
895QString QDirListing::DirEntry::filePath() const
896{
897 return dirListPtr->currentEntryInfo.filePath();
898}
899
900QString QDirListing::DirEntry::canonicalFilePath() const
901{
902 return dirListPtr->currentEntryInfo.canonicalFilePath();
903}
904
905QString QDirListing::DirEntry::absoluteFilePath() const
906{
907 return dirListPtr->currentEntryInfo.absoluteFilePath();
908}
909
910QString QDirListing::DirEntry::absolutePath() const
911{
912 return dirListPtr->currentEntryInfo.absolutePath();
913}
914
916{
917 return dirListPtr->currentEntryInfo.isDir();
918}
919
921{
922 return dirListPtr->currentEntryInfo.isFile();
923}
924
926{
927 return dirListPtr->currentEntryInfo.isSymLink();
928}
929
931{
932 return dirListPtr->currentEntryInfo.exists();
933}
934
936{
937 return dirListPtr->currentEntryInfo.isHidden();
938}
939
941{
942 return dirListPtr->currentEntryInfo.isReadable();
943}
944
946{
947 return dirListPtr->currentEntryInfo.isWritable();
948}
949
951{
952 return dirListPtr->currentEntryInfo.isExecutable();
953}
954
955qint64 QDirListing::DirEntry::size() const
956{
957 return dirListPtr->currentEntryInfo.size();
958}
959
960QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
961{
962 return dirListPtr->currentEntryInfo.fileTime(type, tz);
963}
964
965QT_END_NAMESPACE
bool entryMatches(QDirEntryInfo &info)
QDirListing::IteratorFlags iteratorFlags
void pushInitialDirectory()
QStringList nameFilters
void checkAndPushDirectory(QDirEntryInfo &info)
void setLegacyFilters(QDir::Filters dirFilters, QDirIterator::IteratorFlags dirIteratorFlags)
std::unique_ptr< QAbstractFileEngine > engine
QDuplicateTracker< QString > visitedLinks
bool hasIterators() const
QDir::Filters legacyDirFilters
bool matchesLegacyFilters(QDirEntryInfo &data) const
bool matchesFilters(QDirEntryInfo &data) const
QDirEntryInfo initialEntryInfo
QDirEntryInfo currentEntryInfo
std::vector< FEngineIteratorPtr > fileEngineIterators
std::vector< FsIteratorPtr > nativeIterators
void pushDirectory(QDirEntryInfo &info)
void init(bool resolveEngine)
\inmodule QtCore
Definition qdirlisting.h:61
Q_CORE_EXPORT bool isReadable() const
Q_CORE_EXPORT bool isHidden() const
Q_CORE_EXPORT bool isWritable() const
Q_CORE_EXPORT bool isExecutable() const
Q_CORE_EXPORT bool isFile() const
Q_CORE_EXPORT bool exists() const
Q_CORE_EXPORT bool isSymLink() const
Q_CORE_EXPORT bool isDir() const
const_iterator & operator++()
Pre-increment operator.
IteratorFlag
This enum class describes flags that can be used to configure the behavior of QDirListing.
Definition qdirlisting.h:27
static bool isDotOrDotDot(QStringView fileName)
static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags)