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