1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | /*! |
5 | \since 4.3 |
6 | \class QDirIterator |
7 | \inmodule QtCore |
8 | \ingroup io |
9 | \brief The QDirIterator class provides an iterator for directory entrylists. |
10 | |
11 | You can use QDirIterator to navigate entries of a directory one at a time. |
12 | It is similar to QDir::entryList() and QDir::entryInfoList(), but because |
13 | it lists entries one at a time instead of all at once, it scales better |
14 | and is more suitable for large directories. It also supports listing |
15 | directory contents recursively, and following symbolic links. Unlike |
16 | QDir::entryList(), QDirIterator does not support sorting. |
17 | |
18 | The QDirIterator constructor takes a QDir or a directory as |
19 | argument. After construction, the iterator is located before the first |
20 | directory entry. Here's how to iterate over all the entries sequentially: |
21 | |
22 | \snippet code/src_corelib_io_qdiriterator.cpp 0 |
23 | |
24 | Here's how to find and read all files filtered by name, recursively: |
25 | |
26 | \snippet code/src_corelib_io_qdiriterator.cpp 1 |
27 | |
28 | The next() and nextFileInfo() functions advance the iterator and return |
29 | the path or the QFileInfo of the next directory entry. You can also call |
30 | filePath() or fileInfo() to get the current file path or QFileInfo without |
31 | first advancing the iterator. The fileName() function returns only the |
32 | name of the file, similar to how QDir::entryList() works. |
33 | |
34 | Unlike Qt's container iterators, QDirIterator is uni-directional (i.e., |
35 | you cannot iterate directories in reverse order) and does not allow random |
36 | access. |
37 | |
38 | \note This class is deprecated and may be removed in a Qt release. Use |
39 | QDirListing instead. |
40 | |
41 | \sa QDir, QDir::entryList() |
42 | */ |
43 | |
44 | /*! \enum QDirIterator::IteratorFlag |
45 | |
46 | This enum describes flags that you can combine to configure the behavior |
47 | of QDirIterator. |
48 | |
49 | \value NoIteratorFlags The default value, representing no flags. The |
50 | iterator will return entries for the assigned path. |
51 | |
52 | \value Subdirectories List entries inside all subdirectories as well. |
53 | |
54 | \value FollowSymlinks When combined with Subdirectories, this flag |
55 | enables iterating through all subdirectories of the assigned path, |
56 | following all symbolic links. Symbolic link loops (e.g., "link" => "." or |
57 | "link" => "..") are automatically detected and ignored. |
58 | */ |
59 | |
60 | #include "qdiriterator.h" |
61 | #include "qdir_p.h" |
62 | #include "qabstractfileengine_p.h" |
63 | #include "qdirlisting.h" |
64 | #include "qdirentryinfo_p.h" |
65 | |
66 | #include <QtCore/qset.h> |
67 | #include <QtCore/qstack.h> |
68 | #include <QtCore/qvariant.h> |
69 | #if QT_CONFIG(regularexpression) |
70 | #include <QtCore/qregularexpression.h> |
71 | #endif |
72 | |
73 | #include <QtCore/private/qfilesystemiterator_p.h> |
74 | #include <QtCore/private/qfilesystementry_p.h> |
75 | #include <QtCore/private/qfilesystemmetadata_p.h> |
76 | #include <QtCore/private/qfilesystemengine_p.h> |
77 | #include <QtCore/private/qfileinfo_p.h> |
78 | #include <QtCore/private/qduplicatetracker_p.h> |
79 | |
80 | #include <memory> |
81 | #include <stack> |
82 | #include <vector> |
83 | |
84 | QT_BEGIN_NAMESPACE |
85 | |
86 | using namespace Qt::StringLiterals; |
87 | |
88 | class QDirIteratorPrivate |
89 | { |
90 | public: |
91 | QDirIteratorPrivate(const QString &path, const QStringList &nameFilters = {}, |
92 | QDir::Filters filters = QDir::NoFilter, |
93 | QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags) |
94 | : lister(path, nameFilters, filters.toInt(), flags.toInt()) |
95 | { init(); } |
96 | |
97 | void init() |
98 | { |
99 | it = lister.begin(); |
100 | if (it != lister.end()) |
101 | nextFileInfo = it->fileInfo(); |
102 | } |
103 | |
104 | void advance() |
105 | { |
106 | // Match the behavior of advance() from before porting to QDirListing, |
107 | // that is, even if hasNext() returns false, calling next() returns an |
108 | // empty string without crashing. QTBUG-130142 |
109 | if (it == lister.end()) |
110 | return; |
111 | currentFileInfo = nextFileInfo; |
112 | if (++it != lister.end()) { |
113 | nextFileInfo = it->fileInfo(); |
114 | } |
115 | } |
116 | |
117 | QDirListing lister; |
118 | QDirListing::const_iterator it = {}; |
119 | QFileInfo currentFileInfo; |
120 | QFileInfo nextFileInfo; |
121 | }; |
122 | |
123 | /*! |
124 | Constructs a QDirIterator that can iterate over \a dir's entrylist, using |
125 | \a dir's name filters and regular filters. You can pass options via \a |
126 | flags to decide how the directory should be iterated. |
127 | |
128 | By default, \a flags is NoIteratorFlags, which provides the same behavior |
129 | as in QDir::entryList(). |
130 | |
131 | The sorting in \a dir is ignored. |
132 | |
133 | \note To list symlinks that point to non existing files, QDir::System must be |
134 | passed to the flags. |
135 | |
136 | \sa hasNext(), next(), IteratorFlags |
137 | */ |
138 | QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) |
139 | : d(new QDirIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags)) |
140 | { |
141 | } |
142 | |
143 | /*! |
144 | Constructs a QDirIterator that can iterate over \a path, with no name |
145 | filtering and \a filters for entry filtering. You can pass options via \a |
146 | flags to decide how the directory should be iterated. |
147 | |
148 | By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags, |
149 | which provides the same behavior as in QDir::entryList(). |
150 | |
151 | \note To list symlinks that point to non existing files, QDir::System must be |
152 | passed to the flags. |
153 | |
154 | \sa hasNext(), next(), IteratorFlags |
155 | */ |
156 | QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags) |
157 | : d(new QDirIteratorPrivate(path, {}, filters, flags)) |
158 | { |
159 | } |
160 | |
161 | /*! |
162 | Constructs a QDirIterator that can iterate over \a path. You can pass |
163 | options via \a flags to decide how the directory should be iterated. |
164 | |
165 | By default, \a flags is NoIteratorFlags, which provides the same behavior |
166 | as in QDir::entryList(). |
167 | |
168 | \note To list symlinks that point to non existing files, QDir::System must be |
169 | passed to the flags. |
170 | |
171 | \sa hasNext(), next(), IteratorFlags |
172 | */ |
173 | QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) |
174 | : d(new QDirIteratorPrivate(path, {}, QDir::NoFilter, flags)) |
175 | { |
176 | } |
177 | |
178 | /*! |
179 | Constructs a QDirIterator that can iterate over \a path, using \a |
180 | nameFilters and \a filters. You can pass options via \a flags to decide |
181 | how the directory should be iterated. |
182 | |
183 | By default, \a flags is NoIteratorFlags, which provides the same behavior |
184 | as QDir::entryList(). |
185 | |
186 | For example, the following iterator could be used to iterate over audio |
187 | files: |
188 | |
189 | \snippet code/src_corelib_io_qdiriterator.cpp 2 |
190 | |
191 | \note To list symlinks that point to non existing files, QDir::System must be |
192 | passed to the flags. |
193 | |
194 | \sa hasNext(), next(), IteratorFlags, QDir::setNameFilters() |
195 | */ |
196 | QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters, |
197 | QDir::Filters filters, IteratorFlags flags) |
198 | : d(new QDirIteratorPrivate(path, nameFilters, filters, flags)) |
199 | { |
200 | } |
201 | |
202 | /*! |
203 | Destroys the QDirIterator. |
204 | */ |
205 | QDirIterator::~QDirIterator() |
206 | { |
207 | } |
208 | |
209 | /*! |
210 | Advances the iterator to the next entry, and returns the file path of this |
211 | new entry. If hasNext() returns \c false, this function does nothing, and |
212 | returns an empty QString. |
213 | |
214 | You can call fileName() or filePath() to get the current entry's file name |
215 | or path, or fileInfo() to get a QFileInfo for the current entry. |
216 | |
217 | Call nextFileInfo() instead of next() if you're interested in the QFileInfo. |
218 | |
219 | \sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo() |
220 | */ |
221 | QString QDirIterator::next() |
222 | { |
223 | d->advance(); |
224 | return d->currentFileInfo.filePath(); |
225 | } |
226 | |
227 | /*! |
228 | \since 6.3 |
229 | |
230 | Advances the iterator to the next entry, and returns the file info of this |
231 | new entry. If hasNext() returns \c false, this function does nothing, and |
232 | returns an empty QFileInfo. |
233 | |
234 | You can call fileName() or filePath() to get the current entry's file name |
235 | or path, or fileInfo() to get a QFileInfo for the current entry. |
236 | |
237 | Call next() instead of nextFileInfo() when all you need is the filePath(). |
238 | |
239 | \sa hasNext(), fileName(), filePath(), fileInfo() |
240 | */ |
241 | QFileInfo QDirIterator::nextFileInfo() |
242 | { |
243 | d->advance(); |
244 | return d->currentFileInfo; |
245 | } |
246 | |
247 | /*! |
248 | Returns \c true if there is at least one more entry in the directory; |
249 | otherwise, false is returned. |
250 | |
251 | \sa next(), nextFileInfo(), fileName(), filePath(), fileInfo() |
252 | */ |
253 | bool QDirIterator::hasNext() const |
254 | { |
255 | return d->it != d->lister.end(); |
256 | } |
257 | |
258 | /*! |
259 | Returns the file name for the current directory entry, without the path |
260 | prepended. |
261 | |
262 | This function is convenient when iterating a single directory. When using |
263 | the QDirIterator::Subdirectories flag, you can use filePath() to get the |
264 | full path. |
265 | |
266 | \sa filePath(), fileInfo() |
267 | */ |
268 | QString QDirIterator::fileName() const |
269 | { |
270 | return d->currentFileInfo.fileName(); |
271 | } |
272 | |
273 | /*! |
274 | Returns the full file path for the current directory entry. |
275 | |
276 | \sa fileInfo(), fileName() |
277 | */ |
278 | QString QDirIterator::filePath() const |
279 | { |
280 | return d->currentFileInfo.filePath(); |
281 | } |
282 | |
283 | /*! |
284 | Returns a QFileInfo for the current directory entry. |
285 | |
286 | \sa filePath(), fileName() |
287 | */ |
288 | QFileInfo QDirIterator::fileInfo() const |
289 | { |
290 | return d->currentFileInfo; |
291 | } |
292 | |
293 | /*! |
294 | Returns the base directory of the iterator. |
295 | */ |
296 | QString QDirIterator::path() const |
297 | { |
298 | return d->lister.iteratorPath(); |
299 | } |
300 | |
301 | QT_END_NAMESPACE |
302 | |