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 auto *native = std::get_if<QDirEntryInfo::Native>(&initialEntryInfo.content);
239 Q_ASSERT(native);
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.emplace();
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([this](auto &e) { return matchesFilters(e); },
543 entryInfo.content);
544}
545
547{
548 if (engine)
549 return !fileEngineIterators.empty();
550
551#if !defined(QT_NO_FILESYSTEMITERATOR)
552 return !nativeIterators.empty();
553#endif
554
555 return false;
556}
557
558/*!
559 Constructs a QDirListing that can iterate over \a path.
560
561 You can pass options via \a flags to control how the directory should
562 be iterated.
563
564 By default, \a flags is IteratorFlag::Default.
565
566 \sa IteratorFlags
567*/
568QDirListing::QDirListing(const QString &path, IteratorFlags flags)
569 : d(new QDirListingPrivate)
570{
571 d->initialEntryInfo.content = QDirEntryInfo::Native { QFileSystemEntry(path), {} };
572 d->iteratorFlags = flags;
573 d->init();
574}
575
576/*!
577 Constructs a QDirListing that can iterate over \a path.
578
579 You can pass options via \a flags to control how the directory should
580 be iterated. By default, \a flags is IteratorFlag::Default.
581
582 The listed entries will be filtered according to the file glob patterns
583 in \a nameFilters, which are converted to a regular expression using
584 QRegularExpression::fromWildcard (see QDir::setNameFilters() for more
585 details).
586
587 For example, the following iterator could be used to iterate over audio
588 files:
589
590 \snippet code/src_corelib_io_qdirlisting.cpp 2
591
592 Sometimes you can filter by name more efficiently by iterating over the
593 entries with a range-for loop, using string comparison. For example:
594
595 \snippet code/src_corelib_io_qdirlisting.cpp 7
596
597 \sa IteratorFlags, QDir::setNameFilters()
598*/
599QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, IteratorFlags flags)
600 : d(new QDirListingPrivate)
601{
602 d->initialEntryInfo.content = QDirEntryInfo::Native { QFileSystemEntry(path), {} };
603 d->nameFilters = nameFilters;
604 d->iteratorFlags = flags;
605 d->init();
606}
607
608/*!
609 \fn QDirListing::QDirListing(QDirListing &&other)
610
611 Move constructor. Moves \a other into this QDirListing.
612
613//! [partially-formed]
614 \note The moved-from object \a other is placed in a partially-formed state,
615 in which the only valid operations are destruction and assignment of a new
616 value.
617//! [partially-formed]
618*/
619
620/*!
621 \fn QDirListing &QDirListing::operator=(QDirListing &&other)
622
623 Move-assigns \a other to this QDirListing.
624
625 \include qdirlisting.cpp partially-formed
626*/
627
628/*!
629 Destroys the QDirListing.
630*/
631QDirListing::~QDirListing()
632{
633 delete d;
634}
635
636/*!
637 Returns the directory path used to construct this QDirListing.
638*/
639QString QDirListing::iteratorPath() const
640{
641 return d->initialEntryInfo.filePath();
642}
643
644/*!
645 Returns the set of IteratorFlags used to construct this QDirListing.
646*/
647QDirListing::IteratorFlags QDirListing::iteratorFlags() const
648{
649 return d->iteratorFlags;
650}
651
652/*!
653 Returns the list of file name glob filters used to construct this
654 QDirListing.
655*/
656QStringList QDirListing::nameFilters() const
657{
658 return d->nameFilters;
659}
660
661/*!
662 \class QDirListing::const_iterator
663 \since 6.8
664 \inmodule QtCore
665 \ingroup io
666
667 The iterator type returned by QDirListing::cbegin().
668
669//! [dirlisting-iterator-behavior]
670 \list
671 \li This is a forward-only, single-pass iterator (you cannot iterate
672 directory entries in reverse order)
673 \li Can't be copied, only \c{std::move()}d.
674 \li \include qdirlisting.cpp post-increment-partially-formed
675 \li Doesn't allow random access
676 \li Can be used in ranged-for loops; or with C++20 std::ranges algorithms
677 that don't require random access iterators
678 \li Dereferencing a valid iterator returns a \c{const DirEntry &}
679 \li (c)end() returns a \l QDirListing::sentinel that signals the end of
680 the iteration. Dereferencing an iterator that compares equal to end()
681 is undefined behavior
682 \endlist
683//! [dirlisting-iterator-behavior]
684
685 \include qdirlisting.cpp ranges-algorithms-note
686
687 \sa QDirListing, QDirListing::sentinel, QDirListing::DirEntry
688*/
689
690/*!
691 \typealias QDirListing::const_iterator::reference
692
693 A typedef for \c {const QDirListing::DirEntry &}.
694*/
695
696/*!
697 \typealias QDirListing::const_iterator::pointer
698
699 A typedef for \c {const QDirListing::DirEntry *}.
700*/
701
702/*!
703 \class QDirListing::sentinel
704 \since 6.8
705 \inmodule QtCore
706 \ingroup io
707
708 \l QDirListing returns an object of this type to signal the end of
709 iteration. Dereferencing a \l QDirListing::const_iterator that is
710 equal to \c sentinel{} is undefined behavior.
711
712 \include qdirlisting.cpp ranges-algorithms-note
713
714 \sa QDirListing, QDirListing::const_iterator, QDirListing::DirEntry
715*/
716
717/*!
718 \fn QDirListing::const_iterator QDirListing::begin() const
719 \fn QDirListing::const_iterator QDirListing::cbegin() const
720 \fn QDirListing::sentinel QDirListing::end() const
721 \fn QDirListing::sentinel QDirListing::cend() const
722
723 (c)begin() returns a QDirListing::const_iterator that can be used to
724 iterate over directory entries.
725
726 \include qdirlisting.cpp dirlisting-iterator-behavior
727
728 \note Each time (c)begin() is called on the same QDirListing object,
729 the internal state is reset and the iteration starts anew.
730
731 (Some of the above restrictions are dictated by the underlying system
732 library functions' implementation).
733
734 For example:
735 \snippet code/src_corelib_io_qdirlisting.cpp 0
736
737 Here's how to find and read all files filtered by name, recursively:
738 \snippet code/src_corelib_io_qdirlisting.cpp 1
739
740//! [ranges-algorithms-note]
741 \note The "classical" STL algorithms don't support iterator/sentinel, so
742 you need to use C++20 std::ranges algorithms for QDirListing, or else a
743 3rd-party library that provides range-based algorithms in C++17.
744//! [ranges-algorithms-note]
745
746 \sa QDirListing::DirEntry
747*/
749{
751 const_iterator it{d};
752 ++it;
753 return it;
754}
755
756/*!
757 \fn const QDirListing::DirEntry &QDirListing::const_iterator::operator*() const
758
759 Returns a \c{const QDirListing::DirEntry &} of the directory entry this
760 iterator points to.
761*/
762
763/*!
764 \fn const QDirListing::DirEntry *QDirListing::const_iterator::operator->() const
765
766 Returns a \c{const QDirListing::DirEntry *} to the directory entry this
767 iterator points to.
768*/
769
770/*!
771 \fn QDirListing::const_iterator::operator++()
772
773 Pre-increment operator.
774 Advances the iterator and returns a reference to it.
775*/
776
777/*!
778 \fn void QDirListing::const_iterator::operator++(int)
779
780 Post-increment operator.
781
782 \include qdirlisting.cpp std-input-iterator-tag
783
784//! [post-increment-partially-formed]
785 The return value of post-increment on objects that model
786 \c std::input_iterator is partially-formed (a copy of an iterator that
787 has since been advanced), the only valid operations on such an object
788 are destruction and assignment of a new iterator. Therefore the
789 post-increment operator advances the iterator and returns \c void.
790//! [post-increment-partially-formed]
791*/
792
793/*!
794 \internal
795
796 Implements the actual advancing. Not a member function to avoid forcing
797 DirEntry objects (and therefore const_iterator ones) onto the stack.
798*/
799auto QDirListing::next(DirEntry dirEntry) -> DirEntry
800{
801 dirEntry.dirListPtr->advance();
802 if (!dirEntry.dirListPtr->hasIterators())
803 return {}; // All done, make `this` equal to the end() iterator
804 return dirEntry;
805}
806
807/*!
808 \class QDirListing::DirEntry
809 \inmodule QtCore
810 \ingroup io
811
812 Dereferencing a valid QDirListing::const_iterator returns a DirEntry
813 object.
814
815 DirEntry offers a subset of QFileInfo's API (for example, fileName(),
816 filePath(), exists()). Internally, DirEntry only constructs a QFileInfo
817 object if needed, that is, if the info hasn't been already fetched
818 by other system functions. You can use DirEntry::fileInfo() to get a
819 QFileInfo. For example:
820
821 \snippet code/src_corelib_io_qdirlisting.cpp 3
822
823 \snippet code/src_corelib_io_qdirlisting.cpp 4
824*/
825
826/*!
827 \fn QFileInfo QDirListing::DirEntry::fileInfo() const
828 \fn QString QDirListing::DirEntry::fileName() const
829 \fn QString QDirListing::DirEntry::baseName() const
830 \fn QString QDirListing::DirEntry::completeBaseName() const
831 \fn QString QDirListing::DirEntry::suffix() const
832 \fn QString QDirListing::DirEntry::bundleName() const
833 \fn QString QDirListing::DirEntry::completeSuffix() const
834 \fn QString QDirListing::DirEntry::filePath() const
835 \fn QString QDirListing::DirEntry::canonicalFilePath() const
836 \fn QString QDirListing::DirEntry::absoluteFilePath() const
837 \fn QString QDirListing::DirEntry::absolutePath() const
838 \fn bool QDirListing::DirEntry::isDir() const
839 \fn bool QDirListing::DirEntry::isFile() const
840 \fn bool QDirListing::DirEntry::isSymLink() const
841 \fn bool QDirListing::DirEntry::exists() const
842 \fn bool QDirListing::DirEntry::isHidden() const
843 \fn bool QDirListing::DirEntry::isReadable() const
844 \fn bool QDirListing::DirEntry::isWritable() const
845 \fn bool QDirListing::DirEntry::isExecutable() const
846 \fn qint64 QDirListing::DirEntry::size() const
847 \fn QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
848 \fn QDateTime QDirListing::DirEntry::birthTime(const QTimeZone &tz) const;
849 \fn QDateTime QDirListing::DirEntry::metadataChangeTime(const QTimeZone &tz) const;
850 \fn QDateTime QDirListing::DirEntry::lastModified(const QTimeZone &tz) const;
851 \fn QDateTime QDirListing::DirEntry::lastRead(const QTimeZone &tz) const;
852
853 See the QFileInfo methods with the same names.
854*/
855
856QFileInfo QDirListing::DirEntry::fileInfo() const
857{
858 return dirListPtr->currentEntryInfo.fileInfo();
859}
860
861QString QDirListing::DirEntry::fileName() const
862{
863 return dirListPtr->currentEntryInfo.fileName();
864}
865
866QString QDirListing::DirEntry::baseName() const
867{
868 return dirListPtr->currentEntryInfo.baseName();
869}
870
871QString QDirListing::DirEntry::completeBaseName() const
872{
873 return dirListPtr->currentEntryInfo.completeBaseName();
874}
875
876QString QDirListing::DirEntry::suffix() const
877{
878 return dirListPtr->currentEntryInfo.suffix();
879}
880
881QString QDirListing::DirEntry::bundleName() const
882{
883 return dirListPtr->currentEntryInfo.bundleName();
884}
885
886QString QDirListing::DirEntry::completeSuffix() const
887{
888 return dirListPtr->currentEntryInfo.completeSuffix();
889}
890
891QString QDirListing::DirEntry::filePath() const
892{
893 return dirListPtr->currentEntryInfo.filePath();
894}
895
896QString QDirListing::DirEntry::canonicalFilePath() const
897{
898 return dirListPtr->currentEntryInfo.canonicalFilePath();
899}
900
901QString QDirListing::DirEntry::absoluteFilePath() const
902{
903 return dirListPtr->currentEntryInfo.absoluteFilePath();
904}
905
906QString QDirListing::DirEntry::absolutePath() const
907{
908 return dirListPtr->currentEntryInfo.absolutePath();
909}
910
912{
913 return dirListPtr->currentEntryInfo.isDir();
914}
915
917{
918 return dirListPtr->currentEntryInfo.isFile();
919}
920
922{
923 return dirListPtr->currentEntryInfo.isSymLink();
924}
925
927{
928 return dirListPtr->currentEntryInfo.exists();
929}
930
932{
933 return dirListPtr->currentEntryInfo.isHidden();
934}
935
937{
938 return dirListPtr->currentEntryInfo.isReadable();
939}
940
942{
943 return dirListPtr->currentEntryInfo.isWritable();
944}
945
947{
948 return dirListPtr->currentEntryInfo.isExecutable();
949}
950
951qint64 QDirListing::DirEntry::size() const
952{
953 return dirListPtr->currentEntryInfo.size();
954}
955
956QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
957{
958 return dirListPtr->currentEntryInfo.fileTime(type, tz);
959}
960
961QT_END_NAMESPACE
bool entryMatches(QDirEntryInfo &info)
QDirListing::IteratorFlags iteratorFlags
void pushInitialDirectory()
QStringList nameFilters
void checkAndPushDirectory(QDirEntryInfo &info)
std::optional< QDuplicateTracker< QString > > visitedLinks
std::unique_ptr< QAbstractFileEngine > engine
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)