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 <variant>
158#include <vector>
159
160QT_BEGIN_NAMESPACE
161
162using namespace Qt::StringLiterals;
163
165{
167public:
169
170 // the default for std::stack is std::deque, but std::vector is more apt:
171 template <typename T>
173 {
174 using Base = std::stack<T, std::vector<T>>;
175 using Base::Base;
176 void clear() { this->c.clear(); } // std::stack is also missing clear()
177 };
178
179 void init();
180 void advance();
182
186
188 bool matchesFilters(QDirEntryInfo &data) const;
189 bool hasIterators() const;
190
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
207 // QDirListing scans either through a QAbstractFileEngine (resources, custom
208 // engines) or natively (QFileSystemEngine + QFileSystemIterator). The mode
209 // is selected by beginIterating().
217 struct NativeData {
218#ifndef QT_NO_FILESYSTEMITERATOR
222#else
223 NativeData() noexcept
224 { qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!"); }
225#endif
226 };
227 std::variant<std::monostate, EngineData, NativeData> data;
228
229private:
230 bool matchesFilters(const QFileInfo &fileInfo) const;
231 bool matchesFilters(QDirEntryInfo::Iterator &iterator) const;
232 bool matchesFilters(const QFileInfo &fileInfo, const QString &fileName) const;
233 bool matchesFilters(QDirEntryInfo::Native &native) const;
234};
235
237{
238 if (nameFilters.contains("*"_L1))
239 nameFilters.clear();
240
241#if QT_CONFIG(regularexpression)
242 nameRegExps.reserve(size_t(nameFilters.size()));
243
244 const bool isCase = iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::CaseSensitive);
245 const auto cs = isCase ? Qt::CaseSensitive : Qt::CaseInsensitive;
246 for (const auto &filter : std::as_const(nameFilters))
247 nameRegExps.emplace_back(QRegularExpression::fromWildcard(filter, cs));
248#endif
249}
250
251/*!
252 \internal
253
254 Resets the iteration state (if any), so that calling begin()/cbegin()
255 always starts iterating anew.
256*/
258{
259 Q_ASSERT(std::holds_alternative<QDirEntryInfo::Native>(initialEntryInfo.content));
260 QDirEntryInfo::Native &native = *std::get_if<QDirEntryInfo::Native>(&initialEntryInfo.content);
261
262 // (Re-)select our operating mode. Note how std::variant::emplace will
263 // recreate the object even if it matches the current type, which is
264 // necessary for QDuplicateTracker.
265 if (auto engine = QFileSystemEngine::createLegacyEngine(native.entry, native.metaData))
266 data.emplace<EngineData>(std::move(engine));
267 else
268 data.emplace<NativeData>();
269
270 pushDirectory(initialEntryInfo);
271}
272
274{
275 const bool followSymlinks =
276 iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowDirSymlinks);
277
278 if (auto *d = std::get_if<EngineData>(&data)) {
279 const QString path = [&entryInfo] {
280#ifdef Q_OS_WIN
281 if (entryInfo.isSymLink())
282 return entryInfo.canonicalFilePath();
283#endif
284 return entryInfo.filePath();
285 }();
286
287 // Stop link loops
288 if (followSymlinks && d->visitedLinks.hasSeen(entryInfo.canonicalFilePath()))
289 return;
290
291 d->engine->setFileName(path);
292 if (auto it = d->engine->beginEntryList(path, iteratorFlags, nameFilters)) {
293 d->iterators.push(std::move(it));
294 } else {
295 // No iterator; no entry list.
296 }
297 } else if (auto *d = std::get_if<NativeData>(&data); true) {
298 Q_ASSERT(d);
299#ifndef QT_NO_FILESYSTEMITERATOR
300 // In native mode, entryInfo is always Native: the initial entry is
301 // (see beginIterating()) and QFileSystemIterator::advance() only ever
302 // produces Native entries.
303 Q_ASSERT(std::holds_alternative<QDirEntryInfo::Native>(entryInfo.content));
304 const auto native = std::get_if<QDirEntryInfo::Native>(&entryInfo.content);
305 auto it = std::make_unique<QFileSystemIterator>(native->entry, iteratorFlags);
306
307 // Stop link loops
308 if (followSymlinks) {
309 QFileSystemNativeId id = it->nativeId();
310 if (id.isValid() && d->visitedLinks.hasSeen(id))
311 return;
312 }
313
314 d->iterators.push(std::move(it));
315#endif
316 }
317}
318
320{
322 return matchesFilters(entryInfo);
323}
324
325/*!
326 \internal
327
328 Advances the internal iterator, either a QAbstractFileEngineIterator (e.g.
329 QResourceFileEngineIterator) or a QFileSystemIterator (which uses low-level
330 system methods, e.g. readdir() on Unix). The iterators are stored in a
331 stack.
332
333 A typical example of doing recursive iteration:
334 - while iterating directory A we find a sub-dir B
335 - an iterator for B is pushed to the stack
336 - B's iterator is processed (stack.top()) first; then the loop
337 goes back to processing A's iterator
338*/
340{
341 if (auto *d = std::get_if<EngineData>(&data)) {
342 while (!d->iterators.empty()) {
343 // Find the next valid iterator that matches the filters.
344 // Always use top() because entryMatches() may modify `iterators`!
345 while (d->iterators.top()->advance()) {
346 QDirEntryInfo entryInfo{d->iterators.top().get()};
347 if (entryMatches(entryInfo)) {
348 currentEntryInfo = std::move(entryInfo);
349 return;
350 }
351 }
352
353 d->iterators.pop();
354 }
355 } else if (auto *d = std::get_if<NativeData>(&data); true) {
356 Q_ASSERT(d);
357#ifndef QT_NO_FILESYSTEMITERATOR
358 while (!d->iterators.empty()) {
359 // Find the next valid iterator that matches the filters.
360 // Always use top() because entryMatches() may modify `iterators`!
361 while (std::optional r = d->iterators.top()->advance()) {
362 if (entryMatches(*r)) {
363 currentEntryInfo = std::move(*r);
364 return;
365 }
366 }
367
368 d->iterators.pop();
369 }
370#endif
371 }
372}
373
374static bool isDotOrDotDot(QStringView fileName)
375{
376 return fileName == "."_L1 || fileName == ".."_L1;
377}
378
380{
381 using F = QDirListing::IteratorFlag;
382 // If we're doing flat iteration, we're done.
383 if (!iteratorFlags.testAnyFlags(F::Recursive))
384 return;
385
386 // Follow symlinks only when asked
387 if (!iteratorFlags.testAnyFlags(F::FollowDirSymlinks) && entryInfo.isSymLink())
388 return;
389
390 // Never follow . and ..
391 if (isDotOrDotDot(entryInfo.fileName()))
392 return;
393
394 // No hidden directories unless requested
395 const bool includeHidden = iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::IncludeHidden);
396 if (!includeHidden && entryInfo.isHidden())
397 return;
398
399 // Never follow non-directory entries
400 if (!entryInfo.isDir())
401 return;
402
403 pushDirectory(entryInfo);
404}
405
406bool QDirListingPrivate::matchesFilters(QDirEntryInfo::Native &native) const
407{
408 using F = QDirListing::IteratorFlag;
409 using M = QFileSystemMetaData;
410
411 const QString fileName = native.entry.fileName();
412 if (fileName.isEmpty())
413 return false;
414
415 // name filter
416#if QT_CONFIG(regularexpression)
417 const bool skipNameFilters = iteratorFlags.testAnyFlags(F::NoNameFiltersForDirs)
418 && native.ensureFilled(M::DirectoryType).isDirectory();
419 if (!skipNameFilters) {
420 if (!regexMatchesName(fileName))
421 return false;
422 }
423#endif // QT_CONFIG(regularexpression)
424
425 if (isDotOrDotDot(fileName))
426 return iteratorFlags.testFlags(F::IncludeDotAndDotDot);
427
428 if (!iteratorFlags.testAnyFlag(F::IncludeHidden)
429 && native.ensureFilled(M::HiddenAttribute).isHidden()) {
430 return false;
431 }
432
433 if (iteratorFlags.testAnyFlags(F::IncludeBrokenSymlinks)
434 && native.ensureFilled(M::LegacyLinkType).isLegacyLink()
435 && !native.ensureFilled(M::ExistsAttribute).exists()) {
436 return true;
437 }
438
439 if (iteratorFlags.testFlag(F::ResolveSymlinks)) {
440 if (native.ensureFilled(M::LegacyLinkType).isLegacyLink()
441 && !native.ensureFilled(M::ExistsAttribute).exists()) {
442 return false; // Exclude broken symlinks; anything else will be filtered below
443 }
444 } else {
445 constexpr auto f = F::ExcludeFiles | F::ExcludeDirs | F::ExcludeOther;
446 const bool filterByTargetType = iteratorFlags.testAnyFlags(f);
447 if (filterByTargetType && native.ensureFilled(M::LegacyLinkType).isLegacyLink())
448 return false;
449 }
450
451 if (iteratorFlags.testAnyFlag(F::ExcludeOther)
452 && !native.ensureFilled(M::FileType).isFile()
453 && !native.ensureFilled(M::DirectoryType).isDirectory()
454 && !native.ensureFilled(M::LegacyLinkType).isLegacyLink()) {
455 return false;
456 }
457
458 if (iteratorFlags.testAnyFlags(F::ExcludeDirs)
459 && native.ensureFilled(M::DirectoryType).isDirectory()) {
460 return false;
461 }
462
463 if (iteratorFlags.testAnyFlags(F::ExcludeFiles) && native.ensureFilled(M::FileType).isFile())
464 return false;
465
466 return true;
467}
468
469bool QDirListingPrivate::matchesFilters(const QFileInfo &fileInfo, const QString &fileName) const
470{
471 using F = QDirListing::IteratorFlag;
472
473 Q_ASSERT(!fileName.isEmpty());
474
475 // name filter
476#if QT_CONFIG(regularexpression)
477 const bool skipNameFilters = iteratorFlags.testFlag(F::NoNameFiltersForDirs)
478 && fileInfo.isDir();
479 if (!skipNameFilters) {
480 if (!regexMatchesName(fileName))
481 return false;
482 }
483#endif // QT_CONFIG(regularexpression)
484
485 if (isDotOrDotDot(fileName))
486 return iteratorFlags.testFlag(F::IncludeDotAndDotDot);
487
488 if (!iteratorFlags.testFlag(F::IncludeHidden) && fileInfo.isHidden())
489 return false;
490
491 const bool includeBrokenSymlinks = iteratorFlags.testAnyFlags(F::IncludeBrokenSymlinks);
492 if (includeBrokenSymlinks && fileInfo.isSymLink() && !fileInfo.exists())
493 return true;
494
495 if (iteratorFlags.testFlag(F::ResolveSymlinks)) {
496 if (fileInfo.isSymLink() && !fileInfo.exists())
497 return false; // Exclude broken symlinks; anything else will be filtered below
498 } else {
499 constexpr auto f = F::ExcludeFiles | F::ExcludeDirs | F::ExcludeOther;
500 const bool filterByTargetType = iteratorFlags.testAnyFlags(f);
501 if (filterByTargetType && fileInfo.isSymLink())
502 return false;
503 }
504
505 if (iteratorFlags.testFlag(F::ExcludeOther)
506 && !fileInfo.isFile() && !fileInfo.isDir() && !fileInfo.isSymLink()) {
507 return false;
508 }
509
510 if (iteratorFlags.testFlag(F::ExcludeDirs) && fileInfo.isDir())
511 return false;
512
513 if (iteratorFlags.testFlag(F::ExcludeFiles) && fileInfo.isFile())
514 return false;
515
516 return true;
517}
518
519bool QDirListingPrivate::matchesFilters(QDirEntryInfo::Iterator &iterator) const
520{
521 using F = QDirListing::IteratorFlag;
522
523 const QString fileName = iterator.iterator->currentFileName();
524 if (fileName.isEmpty())
525 return false;
526
527 // Fast path that doesn't require conversion to QFileInfo
528 if (iteratorFlags.testFlag(F::IncludeHidden)
529 && !iteratorFlags.testAnyFlags(
530 F::NoNameFiltersForDirs |
531 F::IncludeBrokenSymlinks |
532 F::ResolveSymlinks |
533 F::ExcludeFiles |
534 F::ExcludeDirs |
535 F::ExcludeOther)) {
536
537#if QT_CONFIG(regularexpression)
538 if (!regexMatchesName(fileName))
539 return false;
540#endif
541 if (isDotOrDotDot(fileName))
542 return iteratorFlags.testFlags(F::IncludeDotAndDotDot);
543
544 return true;
545 }
546
547 // Conversion to QFileInfo can be expensife, but now we need to do it.
548 return matchesFilters(iterator.ensureFileInfo(), fileName);
549}
550
551bool QDirListingPrivate::matchesFilters(const QFileInfo &fileInfo) const
552{
553 const QString fileName = fileInfo.fileName();
554 return !fileName.isEmpty() && matchesFilters(fileInfo, fileName);
555}
556
557/*!
558 \internal
559
560 This function returns \c true if the current entry matches the filters
561 (i.e., the current entry will be returned as part of the directory
562 iteration); otherwise, \c false is returned.
563*/
565{
566 return std::visit([this](auto &e) { return matchesFilters(e); },
567 entryInfo.content);
568}
569
571{
572 if (auto *d = std::get_if<EngineData>(&data))
573 return !d->iterators.empty();
574
575#if !defined(QT_NO_FILESYSTEMITERATOR)
576 if (auto *d = std::get_if<NativeData>(&data))
577 return !d->iterators.empty();
578#endif
579
580 return false;
581}
582
583/*!
584 Constructs a QDirListing that can iterate over \a path.
585
586 You can pass options via \a flags to control how the directory should
587 be iterated.
588
589 By default, \a flags is IteratorFlag::Default.
590
591 \sa IteratorFlags
592*/
593QDirListing::QDirListing(const QString &path, IteratorFlags flags)
594 : d(new QDirListingPrivate)
595{
596 d->initialEntryInfo.content = QDirEntryInfo::Native { QFileSystemEntry(path), {} };
597 d->iteratorFlags = flags;
598 d->init();
599}
600
601/*!
602 Constructs a QDirListing that can iterate over \a path.
603
604 You can pass options via \a flags to control how the directory should
605 be iterated. By default, \a flags is IteratorFlag::Default.
606
607 The listed entries will be filtered according to the file glob patterns
608 in \a nameFilters, which are converted to a regular expression using
609 QRegularExpression::fromWildcard (see QDir::setNameFilters() for more
610 details).
611
612 For example, the following iterator could be used to iterate over audio
613 files:
614
615 \snippet code/src_corelib_io_qdirlisting.cpp 2
616
617 Sometimes you can filter by name more efficiently by iterating over the
618 entries with a range-for loop, using string comparison. For example:
619
620 \snippet code/src_corelib_io_qdirlisting.cpp 7
621
622 \sa IteratorFlags, QDir::setNameFilters()
623*/
624QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, IteratorFlags flags)
625 : d(new QDirListingPrivate)
626{
627 d->initialEntryInfo.content = QDirEntryInfo::Native { QFileSystemEntry(path), {} };
628 d->nameFilters = nameFilters;
629 d->iteratorFlags = flags;
630 d->init();
631}
632
633/*!
634 \fn QDirListing::QDirListing(QDirListing &&other)
635
636 Move constructor. Moves \a other into this QDirListing.
637
638//! [partially-formed]
639 \note The moved-from object \a other is placed in a partially-formed state,
640 in which the only valid operations are destruction and assignment of a new
641 value.
642//! [partially-formed]
643*/
644
645/*!
646 \fn QDirListing &QDirListing::operator=(QDirListing &&other)
647
648 Move-assigns \a other to this QDirListing.
649
650 \include qdirlisting.cpp partially-formed
651*/
652
653/*!
654 Destroys the QDirListing.
655*/
656QDirListing::~QDirListing()
657{
658 delete d;
659}
660
661/*!
662 Returns the directory path used to construct this QDirListing.
663*/
664QString QDirListing::iteratorPath() const
665{
666 return d->initialEntryInfo.filePath();
667}
668
669/*!
670 Returns the set of IteratorFlags used to construct this QDirListing.
671*/
672QDirListing::IteratorFlags QDirListing::iteratorFlags() const
673{
674 return d->iteratorFlags;
675}
676
677/*!
678 Returns the list of file name glob filters used to construct this
679 QDirListing.
680*/
681QStringList QDirListing::nameFilters() const
682{
683 return d->nameFilters;
684}
685
686/*!
687 \class QDirListing::const_iterator
688 \since 6.8
689 \inmodule QtCore
690 \ingroup io
691
692 The iterator type returned by QDirListing::cbegin().
693
694//! [dirlisting-iterator-behavior]
695 \list
696 \li This is a forward-only, single-pass iterator (you cannot iterate
697 directory entries in reverse order)
698 \li Can't be copied, only \c{std::move()}d.
699 \li \include qdirlisting.cpp post-increment-partially-formed
700 \li Doesn't allow random access
701 \li Can be used in ranged-for loops; or with C++20 std::ranges algorithms
702 that don't require random access iterators
703 \li Dereferencing a valid iterator returns a \c{const DirEntry &}
704 \li (c)end() returns a \l QDirListing::sentinel that signals the end of
705 the iteration. Dereferencing an iterator that compares equal to end()
706 is undefined behavior
707 \endlist
708//! [dirlisting-iterator-behavior]
709
710 \include qdirlisting.cpp ranges-algorithms-note
711
712 \sa QDirListing, QDirListing::sentinel, QDirListing::DirEntry
713*/
714
715/*!
716 \typealias QDirListing::const_iterator::reference
717
718 A typedef for \c {const QDirListing::DirEntry &}.
719*/
720
721/*!
722 \typealias QDirListing::const_iterator::pointer
723
724 A typedef for \c {const QDirListing::DirEntry *}.
725*/
726
727/*!
728 \class QDirListing::sentinel
729 \since 6.8
730 \inmodule QtCore
731 \ingroup io
732
733 \l QDirListing returns an object of this type to signal the end of
734 iteration. Dereferencing a \l QDirListing::const_iterator that is
735 equal to \c sentinel{} is undefined behavior.
736
737 \include qdirlisting.cpp ranges-algorithms-note
738
739 \sa QDirListing, QDirListing::const_iterator, QDirListing::DirEntry
740*/
741
742/*!
743 \fn QDirListing::const_iterator QDirListing::begin() const
744 \fn QDirListing::const_iterator QDirListing::cbegin() const
745 \fn QDirListing::sentinel QDirListing::end() const
746 \fn QDirListing::sentinel QDirListing::cend() const
747
748 (c)begin() returns a QDirListing::const_iterator that can be used to
749 iterate over directory entries.
750
751 \include qdirlisting.cpp dirlisting-iterator-behavior
752
753 \note Each time (c)begin() is called on the same QDirListing object,
754 the internal state is reset and the iteration starts anew.
755
756 (Some of the above restrictions are dictated by the underlying system
757 library functions' implementation).
758
759 For example:
760 \snippet code/src_corelib_io_qdirlisting.cpp 0
761
762 Here's how to find and read all files filtered by name, recursively:
763 \snippet code/src_corelib_io_qdirlisting.cpp 1
764
765//! [ranges-algorithms-note]
766 \note The "classical" STL algorithms don't support iterator/sentinel, so
767 you need to use C++20 std::ranges algorithms for QDirListing, or else a
768 3rd-party library that provides range-based algorithms in C++17.
769//! [ranges-algorithms-note]
770
771 \sa QDirListing::DirEntry
772*/
774{
776 const_iterator it{d};
777 ++it;
778 return it;
779}
780
781/*!
782 \fn const QDirListing::DirEntry &QDirListing::const_iterator::operator*() const
783
784 Returns a \c{const QDirListing::DirEntry &} of the directory entry this
785 iterator points to.
786*/
787
788/*!
789 \fn const QDirListing::DirEntry *QDirListing::const_iterator::operator->() const
790
791 Returns a \c{const QDirListing::DirEntry *} to the directory entry this
792 iterator points to.
793*/
794
795/*!
796 \fn QDirListing::const_iterator::operator++()
797
798 Pre-increment operator.
799 Advances the iterator and returns a reference to it.
800*/
801
802/*!
803 \fn void QDirListing::const_iterator::operator++(int)
804
805 Post-increment operator.
806
807 \include qdirlisting.cpp std-input-iterator-tag
808
809//! [post-increment-partially-formed]
810 The return value of post-increment on objects that model
811 \c std::input_iterator is partially-formed (a copy of an iterator that
812 has since been advanced), the only valid operations on such an object
813 are destruction and assignment of a new iterator. Therefore the
814 post-increment operator advances the iterator and returns \c void.
815//! [post-increment-partially-formed]
816*/
817
818/*!
819 \internal
820
821 Implements the actual advancing. Not a member function to avoid forcing
822 DirEntry objects (and therefore const_iterator ones) onto the stack.
823*/
824auto QDirListing::next(DirEntry dirEntry) -> DirEntry
825{
826 dirEntry.dirListPtr->advance();
827 if (!dirEntry.dirListPtr->hasIterators())
828 return {}; // All done, make `this` equal to the end() iterator
829 return dirEntry;
830}
831
832/*!
833 \class QDirListing::DirEntry
834 \inmodule QtCore
835 \ingroup io
836
837 Dereferencing a valid QDirListing::const_iterator returns a DirEntry
838 object.
839
840 DirEntry offers a subset of QFileInfo's API (for example, fileName(),
841 filePath(), exists()). Internally, DirEntry only constructs a QFileInfo
842 object if needed, that is, if the info hasn't been already fetched
843 by other system functions. You can use DirEntry::fileInfo() to get a
844 QFileInfo. For example:
845
846 \snippet code/src_corelib_io_qdirlisting.cpp 3
847
848 \snippet code/src_corelib_io_qdirlisting.cpp 4
849*/
850
851/*!
852 \fn QFileInfo QDirListing::DirEntry::fileInfo() const
853 \fn QString QDirListing::DirEntry::fileName() const
854 \fn QString QDirListing::DirEntry::baseName() const
855 \fn QString QDirListing::DirEntry::completeBaseName() const
856 \fn QString QDirListing::DirEntry::suffix() const
857 \fn QString QDirListing::DirEntry::bundleName() const
858 \fn QString QDirListing::DirEntry::completeSuffix() const
859 \fn QString QDirListing::DirEntry::filePath() const
860 \fn QString QDirListing::DirEntry::canonicalFilePath() const
861 \fn QString QDirListing::DirEntry::absoluteFilePath() const
862 \fn QString QDirListing::DirEntry::absolutePath() const
863 \fn bool QDirListing::DirEntry::isDir() const
864 \fn bool QDirListing::DirEntry::isFile() const
865 \fn bool QDirListing::DirEntry::isSymLink() const
866 \fn bool QDirListing::DirEntry::exists() const
867 \fn bool QDirListing::DirEntry::isHidden() const
868 \fn bool QDirListing::DirEntry::isReadable() const
869 \fn bool QDirListing::DirEntry::isWritable() const
870 \fn bool QDirListing::DirEntry::isExecutable() const
871 \fn qint64 QDirListing::DirEntry::size() const
872 \fn QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
873 \fn QDateTime QDirListing::DirEntry::birthTime(const QTimeZone &tz) const;
874 \fn QDateTime QDirListing::DirEntry::metadataChangeTime(const QTimeZone &tz) const;
875 \fn QDateTime QDirListing::DirEntry::lastModified(const QTimeZone &tz) const;
876 \fn QDateTime QDirListing::DirEntry::lastRead(const QTimeZone &tz) const;
877
878 See the QFileInfo methods with the same names.
879*/
880
881QFileInfo QDirListing::DirEntry::fileInfo() const
882{
883 return dirListPtr->currentEntryInfo.fileInfo();
884}
885
886QString QDirListing::DirEntry::fileName() const
887{
888 return dirListPtr->currentEntryInfo.fileName();
889}
890
891QString QDirListing::DirEntry::baseName() const
892{
893 return dirListPtr->currentEntryInfo.baseName();
894}
895
896QString QDirListing::DirEntry::completeBaseName() const
897{
898 return dirListPtr->currentEntryInfo.completeBaseName();
899}
900
901QString QDirListing::DirEntry::suffix() const
902{
903 return dirListPtr->currentEntryInfo.suffix();
904}
905
906QString QDirListing::DirEntry::bundleName() const
907{
908 return dirListPtr->currentEntryInfo.bundleName();
909}
910
911QString QDirListing::DirEntry::completeSuffix() const
912{
913 return dirListPtr->currentEntryInfo.completeSuffix();
914}
915
916QString QDirListing::DirEntry::filePath() const
917{
918 return dirListPtr->currentEntryInfo.filePath();
919}
920
921QString QDirListing::DirEntry::canonicalFilePath() const
922{
923 return dirListPtr->currentEntryInfo.canonicalFilePath();
924}
925
926QString QDirListing::DirEntry::absoluteFilePath() const
927{
928 return dirListPtr->currentEntryInfo.absoluteFilePath();
929}
930
931QString QDirListing::DirEntry::absolutePath() const
932{
933 return dirListPtr->currentEntryInfo.absolutePath();
934}
935
937{
938 return dirListPtr->currentEntryInfo.isDir();
939}
940
942{
943 return dirListPtr->currentEntryInfo.isFile();
944}
945
947{
948 return dirListPtr->currentEntryInfo.isSymLink();
949}
950
952{
953 return dirListPtr->currentEntryInfo.exists();
954}
955
957{
958 return dirListPtr->currentEntryInfo.isHidden();
959}
960
962{
963 return dirListPtr->currentEntryInfo.isReadable();
964}
965
967{
968 return dirListPtr->currentEntryInfo.isWritable();
969}
970
972{
973 return dirListPtr->currentEntryInfo.isExecutable();
974}
975
976qint64 QDirListing::DirEntry::size() const
977{
978 return dirListPtr->currentEntryInfo.size();
979}
980
981QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
982{
983 return dirListPtr->currentEntryInfo.fileTime(type, tz);
984}
985
986QT_END_NAMESPACE
bool entryMatches(QDirEntryInfo &info)
QDirListing::IteratorFlags iteratorFlags
void pushInitialDirectory()
std::variant< std::monostate, EngineData, NativeData > data
QStringList nameFilters
void checkAndPushDirectory(QDirEntryInfo &info)
bool hasIterators() const
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)
vector_stack< FEngineIteratorPtr > iterators
QDuplicateTracker< QString > visitedLinks
std::unique_ptr< QAbstractFileEngine > engine
EngineData(std::unique_ptr< QAbstractFileEngine > engine) noexcept
vector_stack< FsIteratorPtr > iterators
QDuplicateTracker< QFileSystemNativeId > visitedLinks