mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-05 16:55:25 +08:00
qt 6.5.1 original
This commit is contained in:
22
tests/benchmarks/corelib/io/qdiriterator/CMakeLists.txt
Normal file
22
tests/benchmarks/corelib/io/qdiriterator/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qdiriterator Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qdiriterator
|
||||
SOURCES
|
||||
tst_bench_qdiriterator.cpp
|
||||
qfilesystemiterator.cpp qfilesystemiterator.h
|
||||
LIBRARIES
|
||||
Qt::Test
|
||||
)
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_extend_target(tst_bench_qdiriterator CONDITION (QT_FEATURE_cxx17_filesystem) AND (GCC AND (QMAKE_GCC_MAJOR_VERSION LESS 9))
|
||||
LINK_OPTIONS
|
||||
"-lstdc++fs"
|
||||
)
|
645
tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp
Normal file
645
tests/benchmarks/corelib/io/qdiriterator/qfilesystemiterator.cpp
Normal file
@ -0,0 +1,645 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
/*!
|
||||
\since 4.5
|
||||
\class QFileSystemIterator
|
||||
\brief The QFileSystemIterator class provides an iterator for directory entrylists.
|
||||
|
||||
You can use QFileSystemIterator to navigate entries of a directory one at a time.
|
||||
It is similar to QDir::entryList() and QDir::entryInfoList(), but because
|
||||
it lists entries one at a time instead of all at once, it scales better
|
||||
and is more suitable for large directories. It also supports listing
|
||||
directory contents recursively, and following symbolic links. Unlike
|
||||
QDir::entryList(), QFileSystemIterator does not support sorting.
|
||||
|
||||
The QFileSystemIterator constructor takes a QDir or a directory as
|
||||
argument. After construction, the iterator is located before the first
|
||||
directory entry. Here's how to iterate over all the entries sequentially:
|
||||
|
||||
\snippet doc/src/snippets/code/src.corelib.io.qdiriterator.cpp 0
|
||||
|
||||
The next() function returns the path to the next directory entry and
|
||||
advances the iterator. You can also call filePath() to get the current
|
||||
file path without advancing the iterator. The fileName() function returns
|
||||
only the name of the file, similar to how QDir::entryList() works. You can
|
||||
also call fileInfo() to get a QFileInfo for the current entry.
|
||||
|
||||
Unlike Qt's container iterators, QFileSystemIterator is uni-directional (i.e.,
|
||||
you cannot iterate directories in reverse order) and does not allow random
|
||||
access.
|
||||
|
||||
QFileSystemIterator works with all supported file engines, and is implemented
|
||||
using QAbstractFileEngineIterator.
|
||||
|
||||
\sa QDir, QDir::entryList(), QAbstractFileEngineIterator
|
||||
*/
|
||||
|
||||
/*! \enum QFileSystemIterator::IteratorFlag
|
||||
|
||||
This enum describes flags that you can combine to configure the behavior
|
||||
of QFileSystemIterator.
|
||||
|
||||
\value NoIteratorFlags The default value, representing no flags. The
|
||||
iterator will return entries for the assigned path.
|
||||
|
||||
\value Subdirectories List entries inside all subdirectories as well.
|
||||
|
||||
\value FollowSymlinks When combined with Subdirectories, this flag
|
||||
enables iterating through all subdirectories of the assigned path,
|
||||
following all symbolic links. Symbolic link loops (e.g., "link" => "." or
|
||||
"link" => "..") are automatically detected and ignored.
|
||||
*/
|
||||
|
||||
#include "qfilesystemiterator.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/qset.h>
|
||||
#include <QtCore/qstack.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QDirIteratorTest {
|
||||
|
||||
class QFileSystemIteratorPrivate
|
||||
{
|
||||
public:
|
||||
QFileSystemIteratorPrivate(const QString &path, const QStringList &nameFilters,
|
||||
QDir::Filters filters, QFileSystemIterator::IteratorFlags flags);
|
||||
~QFileSystemIteratorPrivate();
|
||||
|
||||
void pushSubDirectory(const QByteArray &path);
|
||||
void advance();
|
||||
bool isAcceptable() const;
|
||||
bool shouldFollowDirectory(const QFileInfo &);
|
||||
//bool matchesFilters(const QAbstractFileEngineIterator *it) const;
|
||||
inline bool atEnd() const { return m_dirPaths.isEmpty(); }
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QStack<HANDLE> m_dirStructs;
|
||||
WIN32_FIND_DATA* m_entry;
|
||||
WIN32_FIND_DATA m_fileSearchResult;
|
||||
bool m_bFirstSearchResult;
|
||||
#else
|
||||
QStack<DIR *> m_dirStructs;
|
||||
dirent *m_entry;
|
||||
#endif
|
||||
|
||||
QSet<QString> visitedLinks;
|
||||
QStack<QByteArray> m_dirPaths;
|
||||
QFileInfo fileInfo;
|
||||
QString currentFilePath;
|
||||
QFileSystemIterator::IteratorFlags iteratorFlags;
|
||||
QDir::Filters filters;
|
||||
QStringList nameFilters;
|
||||
|
||||
enum { DontShowDir, ShowDotDotDir, ShowDotDir, ShowDir }
|
||||
m_currentDirShown, m_nextDirShown;
|
||||
|
||||
QFileSystemIterator *q;
|
||||
|
||||
private:
|
||||
bool advanceHelper(); // returns true if we know we have something suitable
|
||||
};
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QFileSystemIteratorPrivate::QFileSystemIteratorPrivate(const QString &path,
|
||||
const QStringList &nameFilters, QDir::Filters filters,
|
||||
QFileSystemIterator::IteratorFlags flags)
|
||||
: iteratorFlags(flags)
|
||||
{
|
||||
if (filters == QDir::NoFilter)
|
||||
filters = QDir::AllEntries;
|
||||
this->filters = filters;
|
||||
this->nameFilters = nameFilters;
|
||||
|
||||
fileInfo.setFile(path);
|
||||
QString dir = fileInfo.isSymLink() ? fileInfo.canonicalFilePath() : path;
|
||||
pushSubDirectory(dir.toLocal8Bit());
|
||||
// skip to acceptable entry
|
||||
while (true) {
|
||||
if (atEnd())
|
||||
return;
|
||||
if (isAcceptable())
|
||||
return;
|
||||
if (advanceHelper())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QFileSystemIteratorPrivate::~QFileSystemIteratorPrivate()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
while (!m_dirStructs.isEmpty())
|
||||
::FindClose(m_dirStructs.pop());
|
||||
#else
|
||||
while (!m_dirStructs.isEmpty())
|
||||
::closedir(m_dirStructs.pop());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static bool isDotOrDotDot(const wchar_t* name)
|
||||
{
|
||||
if (name[0] == L'.' && name[1] == 0)
|
||||
return true;
|
||||
if (name[0] == L'.' && name[1] == L'.' && name[2] == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static bool isDotOrDotDot(const char *name)
|
||||
{
|
||||
if (name[0] == '.' && name[1] == 0)
|
||||
return true;
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QFileSystemIteratorPrivate::pushSubDirectory(const QByteArray &path)
|
||||
{
|
||||
/*
|
||||
if (iteratorFlags & QFileSystemIterator::FollowSymlinks) {
|
||||
if (fileInfo.filePath() != path)
|
||||
fileInfo.setFile(path);
|
||||
if (fileInfo.isSymLink()) {
|
||||
visitedLinks << fileInfo.canonicalFilePath();
|
||||
} else {
|
||||
visitedLinks << fileInfo.absoluteFilePath();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
wchar_t szSearchPath[MAX_PATH];
|
||||
const int end = QString::fromLatin1(path + "\\*").toWCharArray(szSearchPath);
|
||||
Q_ASSERT(end < MAX_PATH);
|
||||
szSearchPath[end] = L'\0';
|
||||
HANDLE dir = FindFirstFile(szSearchPath, &m_fileSearchResult);
|
||||
m_bFirstSearchResult = true;
|
||||
#else
|
||||
DIR *dir = ::opendir(path.constData());
|
||||
//m_entry = ::readdir(dir);
|
||||
//while (m_entry && isDotOrDotDot(m_entry->d_name))
|
||||
// m_entry = ::readdir(m_dirStructs.top());
|
||||
#endif
|
||||
m_dirStructs.append(dir);
|
||||
m_dirPaths.append(path);
|
||||
m_entry = 0;
|
||||
if (filters & QDir::Dirs)
|
||||
m_nextDirShown = ShowDir;
|
||||
else
|
||||
m_nextDirShown = DontShowDir;
|
||||
m_currentDirShown = DontShowDir;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
bool QFileSystemIteratorPrivate::isAcceptable() const
|
||||
{
|
||||
if (!m_entry)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
||||
|
||||
void QFileSystemIteratorPrivate::advance()
|
||||
{
|
||||
while (true) {
|
||||
if (advanceHelper())
|
||||
return;
|
||||
if (atEnd())
|
||||
return;
|
||||
if (isAcceptable())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool QFileSystemIteratorPrivate::advanceHelper()
|
||||
{
|
||||
if (m_dirStructs.isEmpty())
|
||||
return true;
|
||||
|
||||
//printf("ADV %d %d\n", int(m_currentDirShown), int(m_nextDirShown));
|
||||
|
||||
if ((filters & QDir::Dirs)) {
|
||||
m_currentDirShown = m_nextDirShown;
|
||||
if (m_nextDirShown == ShowDir) {
|
||||
//printf("RESTING ON DIR %s %x\n", m_dirPaths.top().constData(), int(filters));
|
||||
m_nextDirShown = (filters & QDir::NoDotAndDotDot) ? DontShowDir : ShowDotDir;
|
||||
// skip start directory itself
|
||||
if (m_dirStructs.size() == 1 && m_currentDirShown == ShowDir)
|
||||
return advanceHelper();
|
||||
return true;
|
||||
}
|
||||
if (m_nextDirShown == ShowDotDir) {
|
||||
//printf("RESTING ON DOT %s %x\n", m_dirPaths.top().constData(), int(filters));
|
||||
m_nextDirShown = ShowDotDotDir;
|
||||
return true;
|
||||
}
|
||||
if (m_nextDirShown == ShowDotDotDir) {
|
||||
//printf("RESTING ON DOTDOT %s %x\n", m_dirPaths.top().constData(), int(filters));
|
||||
m_nextDirShown = DontShowDir;
|
||||
return true;
|
||||
}
|
||||
m_currentDirShown = DontShowDir;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
m_entry = &m_fileSearchResult;
|
||||
if (m_bFirstSearchResult) {
|
||||
m_bFirstSearchResult = false;
|
||||
} else {
|
||||
if (!FindNextFile(m_dirStructs.top(), m_entry))
|
||||
m_entry = 0;
|
||||
}
|
||||
|
||||
while (m_entry && isDotOrDotDot(m_entry->cFileName))
|
||||
if (!FindNextFile(m_dirStructs.top(), m_entry))
|
||||
m_entry = 0;
|
||||
|
||||
if (!m_entry) {
|
||||
m_dirPaths.pop();
|
||||
FindClose(m_dirStructs.pop());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
QByteArray ba = m_dirPaths.top();
|
||||
ba += '\\';
|
||||
ba += QString::fromWCharArray(m_entry->cFileName).toUtf8();
|
||||
pushSubDirectory(ba);
|
||||
}
|
||||
#else
|
||||
m_entry = ::readdir(m_dirStructs.top());
|
||||
while (m_entry && isDotOrDotDot(m_entry->d_name))
|
||||
m_entry = ::readdir(m_dirStructs.top());
|
||||
//return false; // further iteration possibly needed
|
||||
//printf("READ %p %s\n", m_entry, m_entry ? m_entry->d_name : "");
|
||||
|
||||
if (!m_entry) {
|
||||
m_dirPaths.pop();
|
||||
DIR *dir = m_dirStructs.pop();
|
||||
::closedir(dir);
|
||||
return false; // further iteration possibly needed
|
||||
}
|
||||
|
||||
const char *name = m_entry->d_name;
|
||||
|
||||
QByteArray ba = m_dirPaths.top();
|
||||
ba += '/';
|
||||
ba += name;
|
||||
QT_STATBUF st;
|
||||
QT_LSTAT(ba.constData(), &st);
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
pushSubDirectory(ba);
|
||||
return false; // further iteration possibly needed
|
||||
}
|
||||
#endif
|
||||
return false; // further iteration possiblye needed
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
bool QFileSystemIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo)
|
||||
{
|
||||
// If we're doing flat iteration, we're done.
|
||||
if (!(iteratorFlags & QFileSystemIterator::Subdirectories))
|
||||
return false;
|
||||
|
||||
// Never follow non-directory entries
|
||||
if (!fileInfo.isDir())
|
||||
return false;
|
||||
|
||||
|
||||
// Never follow . and ..
|
||||
if (fileInfo.fileName() == QLatin1String(".") || fileInfo.fileName() == QLatin1String(".."))
|
||||
return false;
|
||||
|
||||
|
||||
// Check symlinks
|
||||
if (fileInfo.isSymLink() && !(iteratorFlags & QFileSystemIterator::FollowSymlinks)) {
|
||||
// Follow symlinks only if FollowSymlinks was passed
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stop link loops
|
||||
if (visitedLinks.contains(fileInfo.canonicalFilePath()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
This convenience function implements the iterator's filtering logics and
|
||||
applies then to the current directory entry.
|
||||
|
||||
It returns true if the current entry matches the filters (i.e., the
|
||||
current entry will be returned as part of the directory iteration);
|
||||
otherwise, false is returned.
|
||||
*/
|
||||
#if 0
|
||||
bool QFileSystemIteratorPrivate::matchesFilters(const QAbstractFileEngineIterator *it) const
|
||||
{
|
||||
const bool filterPermissions = ((filters & QDir::PermissionMask)
|
||||
&& (filters & QDir::PermissionMask) != QDir::PermissionMask);
|
||||
const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
|
||||
const bool skipFiles = !(filters & QDir::Files);
|
||||
const bool skipSymlinks = (filters & QDir::NoSymLinks);
|
||||
const bool doReadable = !filterPermissions || (filters & QDir::Readable);
|
||||
const bool doWritable = !filterPermissions || (filters & QDir::Writable);
|
||||
const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
|
||||
const bool includeHidden = (filters & QDir::Hidden);
|
||||
const bool includeSystem = (filters & QDir::System);
|
||||
|
||||
#ifndef QT_NO_REGEXP
|
||||
// Prepare name filters
|
||||
QList<QRegExp> regexps;
|
||||
bool hasNameFilters = !nameFilters.isEmpty() && !(nameFilters.contains(QLatin1String("*")));
|
||||
if (hasNameFilters) {
|
||||
for (int i = 0; i < nameFilters.size(); ++i) {
|
||||
regexps << QRegExp(nameFilters.at(i),
|
||||
(filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
|
||||
QRegExp::Wildcard);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QString fileName = it->currentFileName();
|
||||
if (fileName.isEmpty()) {
|
||||
// invalid entry
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi = it->currentFileInfo();
|
||||
QString filePath = it->currentFilePath();
|
||||
|
||||
#ifndef QT_NO_REGEXP
|
||||
// Pass all entries through name filters, except dirs if the AllDirs
|
||||
// filter is passed.
|
||||
if (hasNameFilters && !((filters & QDir::AllDirs) && fi.isDir())) {
|
||||
bool matched = false;
|
||||
for (int i = 0; i < regexps.size(); ++i) {
|
||||
if (regexps.at(i).exactMatch(fileName)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool dotOrDotDot = (fileName == QLatin1String(".") || fileName == QLatin1String(".."));
|
||||
if ((filters & QDir::NoDotAndDotDot) && dotOrDotDot)
|
||||
return false;
|
||||
|
||||
bool isHidden = !dotOrDotDot && fi.isHidden();
|
||||
if (!includeHidden && isHidden)
|
||||
return false;
|
||||
|
||||
bool isSystem = (!fi.isFile() && !fi.isDir() && !fi.isSymLink())
|
||||
|| (!fi.exists() && fi.isSymLink());
|
||||
if (!includeSystem && isSystem)
|
||||
return false;
|
||||
|
||||
bool alwaysShow = (filters & QDir::TypeMask) == 0
|
||||
&& ((isHidden && includeHidden)
|
||||
|| (includeSystem && isSystem));
|
||||
|
||||
// Skip files and directories
|
||||
if ((filters & QDir::AllDirs) == 0 && skipDirs && fi.isDir()) {
|
||||
if (!alwaysShow)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((skipFiles && (fi.isFile() || !fi.exists()))
|
||||
|| (skipSymlinks && fi.isSymLink())) {
|
||||
if (!alwaysShow)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filterPermissions
|
||||
&& ((doReadable && !fi.isReadable())
|
||||
|| (doWritable && !fi.isWritable())
|
||||
|| (doExecutable && !fi.isExecutable()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!includeSystem && !dotOrDotDot && ((fi.exists() && !fi.isFile() && !fi.isDir() && !fi.isSymLink())
|
||||
|| (!fi.exists() && fi.isSymLink()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a dir's entrylist, using
|
||||
\a dir's name filters and regular filters. You can pass options via \a
|
||||
flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as in QDir::entryList().
|
||||
|
||||
The sorting in \a dir is ignored.
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QDir &dir, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a path, with no name
|
||||
filtering and \a filters for entry filtering. You can pass options via \a
|
||||
flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
|
||||
which provides the same behavior as in QDir::entryList().
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(path, QStringList(QLatin1String("*")), filters, flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a path. You can pass
|
||||
options via \a flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as in QDir::entryList().
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QString &path, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(path, QStringList(QLatin1String("*")), QDir::NoFilter, flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QFileSystemIterator that can iterate over \a path, using \a
|
||||
nameFilters and \a filters. You can pass options via \a flags to decide
|
||||
how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as QDir::entryList().
|
||||
|
||||
\sa atEnd(), next(), IteratorFlags
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QString &path, const QStringList &nameFilters,
|
||||
QDir::Filters filters, IteratorFlags flags)
|
||||
: d(new QFileSystemIteratorPrivate(path, nameFilters, filters, flags))
|
||||
{
|
||||
d->q = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the QFileSystemIterator.
|
||||
*/
|
||||
QFileSystemIterator::~QFileSystemIterator()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*!
|
||||
Advances the iterator to the next entry, and returns the file path of this
|
||||
new entry. If atEnd() returns true, this function does nothing, and
|
||||
returns a null QString.
|
||||
|
||||
You can call fileName() or filePath() to get the current entry file name
|
||||
or path, or fileInfo() to get a QFileInfo for the current entry.
|
||||
|
||||
\sa hasNext(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
void QFileSystemIterator::next()
|
||||
{
|
||||
d->advance();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if there is at least one more entry in the directory;
|
||||
otherwise, false is returned.
|
||||
|
||||
\sa next(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
bool QFileSystemIterator::atEnd() const
|
||||
{
|
||||
return d->atEnd();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the file name for the current directory entry, without the path
|
||||
prepended. If the current entry is invalid (i.e., isValid() returns
|
||||
false), a null QString is returned.
|
||||
|
||||
This function is provided for the convenience when iterating single
|
||||
directories. For recursive iteration, you should call filePath() or
|
||||
fileInfo() instead.
|
||||
|
||||
\sa filePath(), fileInfo()
|
||||
*/
|
||||
QString QFileSystemIterator::fileName() const
|
||||
{
|
||||
if (d->atEnd() || !d->m_entry)
|
||||
return QString();
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDir)
|
||||
return QString();
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDir)
|
||||
return QLatin1String("@");
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDotDir)
|
||||
return QLatin1String("@@");
|
||||
#ifdef Q_OS_WIN
|
||||
return QString::fromWCharArray(d->m_entry->cFileName);
|
||||
#else
|
||||
return QString::fromLocal8Bit(d->m_entry->d_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the full file path for the current directory entry. If the current
|
||||
entry is invalid (i.e., isValid() returns false), a null QString is
|
||||
returned.
|
||||
|
||||
\sa fileInfo(), fileName()
|
||||
*/
|
||||
QString QFileSystemIterator::filePath() const
|
||||
{
|
||||
if (d->atEnd())
|
||||
return QString();
|
||||
QByteArray ba = d->m_dirPaths.top();
|
||||
if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDir)
|
||||
ba += "/.";
|
||||
else if (d->m_currentDirShown == QFileSystemIteratorPrivate::ShowDotDotDir)
|
||||
ba += "/..";
|
||||
else if (d->m_entry) {
|
||||
ba += '/';
|
||||
#ifdef Q_OS_WIN
|
||||
ba += QString::fromWCharArray(d->m_entry->cFileName).toUtf8();
|
||||
#else
|
||||
ba += d->m_entry->d_name;
|
||||
#endif
|
||||
}
|
||||
return QString::fromLocal8Bit(ba);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a QFileInfo for the current directory entry. If the current entry
|
||||
is invalid (i.e., isValid() returns false), a null QFileInfo is returned.
|
||||
|
||||
\sa filePath(), fileName()
|
||||
*/
|
||||
QFileInfo QFileSystemIterator::fileInfo() const
|
||||
{
|
||||
return QFileInfo(filePath());
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the base directory of the iterator.
|
||||
*/
|
||||
QString QFileSystemIterator::path() const
|
||||
{
|
||||
return QString::fromLocal8Bit(d->m_dirPaths.top());
|
||||
}
|
||||
|
||||
} // QDirIteratorTest::
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QFILESYSTEMITERATOR_H
|
||||
#define QFILESYSTEMITERATOR_H
|
||||
|
||||
#include <QtCore/qdir.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QDirIteratorTest {
|
||||
|
||||
class QFileSystemIteratorPrivate;
|
||||
class //Q_CORE_EXPORT
|
||||
QFileSystemIterator
|
||||
{
|
||||
public:
|
||||
enum IteratorFlag {
|
||||
NoIteratorFlags = 0x0,
|
||||
FollowSymlinks = 0x1,
|
||||
Subdirectories = 0x2
|
||||
};
|
||||
Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
|
||||
|
||||
QFileSystemIterator(const QDir &dir, IteratorFlags flags = NoIteratorFlags);
|
||||
QFileSystemIterator(const QString &path,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
QFileSystemIterator(const QString &path,
|
||||
QDir::Filters filter,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
QFileSystemIterator(const QString &path,
|
||||
const QStringList &nameFilters,
|
||||
QDir::Filters filters = QDir::NoFilter,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
|
||||
virtual ~QFileSystemIterator();
|
||||
|
||||
void next();
|
||||
bool atEnd() const;
|
||||
|
||||
QString fileName() const;
|
||||
QString filePath() const;
|
||||
QFileInfo fileInfo() const;
|
||||
QString path() const;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QFileSystemIterator)
|
||||
|
||||
QFileSystemIteratorPrivate *d;
|
||||
friend class QDir;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemIterator::IteratorFlags)
|
||||
|
||||
} // namespace QDirIteratorTest
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
@ -0,0 +1,237 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <QDirIterator>
|
||||
#include <QString>
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
# include <errno.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include <qtest.h>
|
||||
|
||||
#include "qfilesystemiterator.h"
|
||||
|
||||
#if QT_CONFIG(cxx17_filesystem)
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
class tst_QDirIterator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
void data();
|
||||
private slots:
|
||||
void posix();
|
||||
void posix_data() { data(); }
|
||||
void diriterator();
|
||||
void diriterator_data() { data(); }
|
||||
void fsiterator();
|
||||
void fsiterator_data() { data(); }
|
||||
void stdRecursiveDirectoryIterator();
|
||||
void stdRecursiveDirectoryIterator_data() { data(); }
|
||||
};
|
||||
|
||||
void tst_QDirIterator::data()
|
||||
{
|
||||
const char hereRelative[] = "tests/benchmarks/corelib/io/qdiriterator";
|
||||
QByteArray dir(QT_TESTCASE_SOURCEDIR);
|
||||
// qDebug("Source dir: %s", dir.constData());
|
||||
dir.chop(sizeof(hereRelative)); // Counts the '\0', making up for the omitted leading '/'
|
||||
// qDebug("Root dir: %s", dir.constData());
|
||||
|
||||
QTest::addColumn<QByteArray>("dirpath");
|
||||
const QByteArray ba = dir + "/src/corelib";
|
||||
|
||||
if (!QFileInfo(QString::fromLocal8Bit(ba)).isDir())
|
||||
QSKIP("Missing Qt directory");
|
||||
|
||||
QTest::newRow("corelib") << ba;
|
||||
QTest::newRow("corelib/io") << (ba + "/io");
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static int posix_helper(const wchar_t *dirpath, size_t length)
|
||||
{
|
||||
int count = 0;
|
||||
HANDLE hSearch;
|
||||
WIN32_FIND_DATA fd;
|
||||
|
||||
wchar_t appendedPath[MAX_PATH];
|
||||
Q_ASSERT(MAX_PATH > length + 3);
|
||||
wcsncpy(appendedPath, dirpath, length);
|
||||
wcscpy(appendedPath + length, L"\\*");
|
||||
hSearch = FindFirstFile(appendedPath, &fd);
|
||||
|
||||
if (hSearch == INVALID_HANDLE_VALUE) {
|
||||
qWarning("FindFirstFile failed");
|
||||
return count;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!(fd.cFileName[0] == L'.' && fd.cFileName[1] == 0) &&
|
||||
!(fd.cFileName[0] == L'.' && fd.cFileName[1] == L'.' && fd.cFileName[2] == 0))
|
||||
{
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// newLength will "point" to where we put a * earlier, so we overwrite that.
|
||||
size_t newLength = length + 1; // "+ 1" for directory separator
|
||||
Q_ASSERT(newLength + wcslen(fd.cFileName) + 1 < MAX_PATH); // "+ 1" for null-terminator
|
||||
wcscpy(appendedPath + newLength, fd.cFileName);
|
||||
newLength += wcslen(fd.cFileName);
|
||||
count += posix_helper(appendedPath, newLength);
|
||||
}
|
||||
else {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hSearch, &fd));
|
||||
FindClose(hSearch);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int posix_helper(const char *dirpath)
|
||||
{
|
||||
//qDebug() << "DIR" << dirpath;
|
||||
DIR *dir = ::opendir(dirpath);
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
dirent *entry = 0;
|
||||
|
||||
int count = 0;
|
||||
while ((entry = ::readdir(dir))) {
|
||||
if (qstrcmp(entry->d_name, ".") == 0)
|
||||
continue;
|
||||
if (qstrcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
++count;
|
||||
QByteArray ba = dirpath;
|
||||
ba += '/';
|
||||
ba += entry->d_name;
|
||||
QT_STATBUF st;
|
||||
QT_LSTAT(ba.constData(), &st);
|
||||
if (S_ISDIR(st.st_mode))
|
||||
count += posix_helper(ba.constData());
|
||||
}
|
||||
|
||||
::closedir(dir);
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void tst_QDirIterator::posix()
|
||||
{
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
QString path(dirpath);
|
||||
QBENCHMARK {
|
||||
#ifdef Q_OS_WIN
|
||||
wchar_t wPath[MAX_PATH];
|
||||
const int end = path.toWCharArray(wPath);
|
||||
count = posix_helper(wPath, end);
|
||||
#else
|
||||
count = posix_helper(dirpath.constData());
|
||||
#endif
|
||||
}
|
||||
qDebug() << count;
|
||||
}
|
||||
|
||||
void tst_QDirIterator::diriterator()
|
||||
{
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
|
||||
QBENCHMARK {
|
||||
int c = 0;
|
||||
|
||||
QDirIterator dir(dirpath,
|
||||
//QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot,
|
||||
//QDir::AllEntries | QDir::Hidden,
|
||||
QDir::Files,
|
||||
QDirIterator::Subdirectories);
|
||||
|
||||
while (dir.hasNext()) {
|
||||
const auto fi = dir.nextFileInfo();
|
||||
//printf("%s\n", qPrintable(dir.fileName()));
|
||||
0 && printf("%d %s\n",
|
||||
fi.isDir(),
|
||||
//qPrintable(fi.absoluteFilePath()),
|
||||
//qPrintable(dir.path()),
|
||||
qPrintable(fi.filePath()));
|
||||
++c;
|
||||
}
|
||||
count = c;
|
||||
}
|
||||
qDebug() << count;
|
||||
}
|
||||
|
||||
void tst_QDirIterator::fsiterator()
|
||||
{
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
int dump = 0;
|
||||
|
||||
QBENCHMARK {
|
||||
int c = 0;
|
||||
|
||||
dump && printf("\n\n\n\n");
|
||||
QDirIteratorTest::QFileSystemIterator dir(dirpath,
|
||||
//QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot,
|
||||
//QDir::AllEntries | QDir::Hidden,
|
||||
//QDir::Files | QDir::NoDotAndDotDot,
|
||||
QDir::Files,
|
||||
QDirIteratorTest::QFileSystemIterator::Subdirectories);
|
||||
|
||||
for (; !dir.atEnd(); dir.next()) {
|
||||
dump && printf("%d %s\n",
|
||||
dir.fileInfo().isDir(),
|
||||
//qPrintable(dir.fileInfo().absoluteFilePath()),
|
||||
//qPrintable(dir.path()),
|
||||
qPrintable(dir.filePath())
|
||||
);
|
||||
++c;
|
||||
}
|
||||
count = c;
|
||||
}
|
||||
qDebug() << count;
|
||||
}
|
||||
|
||||
void tst_QDirIterator::stdRecursiveDirectoryIterator()
|
||||
{
|
||||
#if QT_CONFIG(cxx17_filesystem)
|
||||
QFETCH(QByteArray, dirpath);
|
||||
|
||||
int count = 0;
|
||||
|
||||
QBENCHMARK {
|
||||
int c = 0;
|
||||
for (auto obj : std::filesystem::recursive_directory_iterator(dirpath.data())) {
|
||||
if (obj.is_directory())
|
||||
continue;
|
||||
c++;
|
||||
}
|
||||
count = c;
|
||||
}
|
||||
qDebug() << count;
|
||||
#else
|
||||
QSKIP("Not supported.");
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QDirIterator)
|
||||
|
||||
#include "tst_bench_qdiriterator.moc"
|
Reference in New Issue
Block a user