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