📄 qdir.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtCore module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qplatformdefs.h"#include "qdir.h"#include "qabstractfileengine.h"#include "qfsfileengine.h"#include "qdatetime.h"#include "qstring.h"#include "qregexp.h"#include "qvector.h"#include <stdlib.h>static QString driveSpec(const QString &path){#ifdef Q_OS_WIN if (path.size() < 2) return QString(); char c = path.at(0).toAscii(); if (c < 'a' && c > 'z' && c < 'A' && c > 'Z') return QString(); if (path.at(1).toAscii() != ':') return QString(); return path.mid(0, 2);#else Q_UNUSED(path); return QString();#endif}//************* QDirPrivateclass QDirPrivate{ QDir *q_ptr; Q_DECLARE_PUBLIC(QDir)protected: QDirPrivate(QDir*, const QDir *copy=0); ~QDirPrivate(); void initFileEngine(const QString &file); void updateFileLists() const; void sortFileList(QDir::SortFlags, QStringList &, QStringList *, QFileInfoList *) const;private:#ifdef QT3_SUPPORT QChar filterSepChar; bool matchAllDirs;#endif static inline QChar getFilterSepChar(const QString &nameFilter) { QChar sep(QLatin1Char(';')); int i = nameFilter.indexOf(sep, 0); if (i == -1 && nameFilter.indexOf(QLatin1Char(' '), 0) != -1) sep = QChar(QLatin1Char(' ')); return sep; } static inline QStringList splitFilters(const QString &nameFilter, QChar sep=0) { if(sep == 0) sep = getFilterSepChar(nameFilter); QStringList ret = nameFilter.split(sep); for(int i = 0; i < ret.count(); i++) ret[i] = ret[i].trimmed(); return ret; } struct Data { inline Data() : ref(1), fileEngine(0) { clear(); } inline Data(const Data ©) : ref(1), path(copy.path), nameFilters(copy.nameFilters), sort(copy.sort), filters(copy.filters), fileEngine(0) { clear(); } inline ~Data() { delete fileEngine; } inline void clear() { listsDirty = 1; } mutable QAtomic ref; QString path; QStringList nameFilters; QDir::SortFlags sort; QDir::Filters filters; mutable QAbstractFileEngine *fileEngine; mutable uint listsDirty : 1; mutable QStringList files; mutable QFileInfoList fileInfos; } *data; inline void setPath(const QString &p) { detach(false); QString path = p; if ((path.endsWith(QLatin1Char('/')) || path.endsWith(QLatin1Char('\\'))) && path.length() > 1) {#ifdef Q_OS_WIN if (!(path.length() == 3 && path.at(1) == ':'))#endif path.truncate(path.length() - 1); } if(!data->fileEngine || !QDir::isRelativePath(path)) initFileEngine(path); data->fileEngine->setFileName(path); // set the path to be the qt friendly version so then we can operate on it using just / data->path = data->fileEngine->fileName(QAbstractFileEngine::DefaultName); data->clear(); } inline void reset() { detach(); data->clear(); } void detach(bool createFileEngine = true);};QDirPrivate::QDirPrivate(QDir *qq, const QDir *copy) : q_ptr(qq)#ifdef QT3_SUPPORT , filterSepChar(0) , matchAllDirs(false)#endif{ if(copy) { copy->d_func()->data->ref.ref(); data = copy->d_func()->data; } else { data = new QDirPrivate::Data; data->clear(); }}QDirPrivate::~QDirPrivate(){ if (!data->ref.deref()) delete data; data = 0; q_ptr = 0;}/* For sorting */struct QDirSortItem { QString filename_cache; QString suffix_cache; QFileInfo item;};static int qt_cmp_si_sort_flags;#if defined(Q_C_CALLBACKS)extern "C" {#endif#ifdef Q_OS_TEMPstatic int __cdecl qt_cmp_si(const void *n1, const void *n2)#elsestatic int qt_cmp_si(const void *n1, const void *n2)#endif{ if (!n1 || !n2) return 0; QDirSortItem* f1 = (QDirSortItem*)n1; QDirSortItem* f2 = (QDirSortItem*)n2; if ((qt_cmp_si_sort_flags & QDir::DirsFirst) && (f1->item.isDir() != f2->item.isDir())) return f1->item.isDir() ? -1 : 1; if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir())) return f1->item.isDir() ? 1 : -1; int r = 0; int sortBy = (qt_cmp_si_sort_flags & QDir::SortByMask) | (qt_cmp_si_sort_flags & QDir::Type); switch (sortBy) { case QDir::Time: r = f1->item.lastModified().secsTo(f2->item.lastModified()); break; case QDir::Size: r = f2->item.size() - f1->item.size(); break; case QDir::Type: { bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase; if (f1->suffix_cache.isNull()) f1->suffix_cache = ic ? f1->item.suffix().toLower() : f1->item.suffix(); if (f2->suffix_cache.isNull()) f2->suffix_cache = ic ? f2->item.suffix().toLower() : f2->item.suffix(); r = qt_cmp_si_sort_flags & QDir::LocaleAware ? f1->suffix_cache.localeAwareCompare(f2->suffix_cache) : f1->suffix_cache.compare(f2->suffix_cache); } break; default: ; } if (r == 0 && sortBy != QDir::Unsorted) { // Still not sorted - sort by name bool ic = qt_cmp_si_sort_flags & QDir::IgnoreCase; if (f1->filename_cache.isNull()) f1->filename_cache = ic ? f1->item.fileName().toLower() : f1->item.fileName(); if (f2->filename_cache.isNull()) f2->filename_cache = ic ? f2->item.fileName().toLower() : f2->item.fileName(); r = qt_cmp_si_sort_flags & QDir::LocaleAware ? f1->filename_cache.localeAwareCompare(f2->filename_cache) : f1->filename_cache.compare(f2->filename_cache); } if (r == 0) // Enforce an order - the order the items appear in the array r = (char*)n1 - (char*)n2; if (qt_cmp_si_sort_flags & QDir::Reversed) return -r; return r;}#if defined(Q_C_CALLBACKS)}#endifinline void QDirPrivate::sortFileList(QDir::SortFlags sort, QStringList &l, QStringList *names, QFileInfoList *infos) const{ if(names) names->clear(); if(infos) infos->clear(); if(!l.isEmpty()) { QDirSortItem *si= new QDirSortItem[l.count()]; int i; for (i = 0; i < l.size(); ++i) { QString path = data->path; if (!path.isEmpty() && !path.endsWith(QLatin1Char('/'))) path += QLatin1Char('/'); si[i].item = QFileInfo(path + l.at(i)); } qt_cmp_si_sort_flags = sort; qsort(si, i, sizeof(si[0]), qt_cmp_si); // put them back in the list(s) for (int j = 0; j<i; j++) { if(infos) infos->append(si[j].item); if(names) names->append(si[j].item.fileName()); } delete [] si; }}inline void QDirPrivate::updateFileLists() const{ if(data->listsDirty) { QStringList l = data->fileEngine->entryList(data->filters, data->nameFilters); sortFileList(data->sort, l, &data->files, &data->fileInfos); data->listsDirty = 0; }}void QDirPrivate::initFileEngine(const QString &path){ detach(false); delete data->fileEngine; data->fileEngine = 0; data->clear(); data->fileEngine = QAbstractFileEngine::create(path);}void QDirPrivate::detach(bool createFileEngine){ qAtomicDetach(data); if (createFileEngine) { delete data->fileEngine; data->fileEngine = QAbstractFileEngine::create(data->path); }}/*! \class QDir \brief The QDir class provides access to directory structures and their contents. \ingroup io \reentrant \mainclass A QDir is used to manipulate path names, access information regarding paths and files, and manipulate the underlying file system. It can also be used to access Qt's \l{resource system}. A QDir can point to a file using either a relative or an absolute path. Absolute paths begin with the directory separator "/" (optionally preceded by a drive specification under Windows). If you always use "/" as a directory separator, Qt will translate your paths to conform to the underlying operating system. Relative file names begin with a directory name or a file name and specify a path relative to the current directory. An example of an absolute path is the string "/tmp/quartz", a relative path might look like "src/fatlib". You can use the isRelative() or isAbsolute() functions to check if a QDir is using a relative or an absolute file path. Call makeAbsolute() to convert a relative QDir to an absolute one. For a simplified path use cleanPath(). To obtain a path which has no symbolic links or redundant ".." elements use canonicalPath(). The path can be set with setPath(), and changed with cd() and cdUp(). The current() path (and currentPath()), refers to the application's working directory. A QDir's own path is set and retrieved with setPath() and path(). QDir provides several static convenience functions, for example, setCurrent() to set the application's working directory and current() and currentPath() to retrieve the application's working directory. Access to some common paths is provided with the static functions, home(), root(), and temp() which return QDir objects or homePath(), rootPath(), and tempPath() which return the path as a string. For the application's directory, see \l{QApplication::applicationDirPath()}. The number of entries in a directory is returned by count(). You can obtain a string list of the names of all the files and directories in a directory with entryList(). If you prefer a list of QFileInfo pointers use entryInfoList(). Both these functions can apply a name filter, an attributes filter (e.g. read-only, files not directories, etc.), and a sort order. The filters and sort may be set with calls to setNameFilters(), setFilter() and setSorting(). They may also be specified in the entryList() and entryInfoList()'s arguments. You can test to see if a filename matches a filter using match(). Create a new directory with mkdir(), rename a directory with rename() and remove an existing directory with rmdir(). Remove a file with remove(). You can query a directory with exists(), isReadable(), isAbsolute(), isRelative(), and isRoot(). You can use refresh() to re-read the directory's data from disk. To get a path with a filename use filePath(), and to get a directory name use dirName(); neither of these functions checks for the existence of the file or directory. The path() (changeable with setPath()), absolutePath(), absoluteFilePath(), and canonicalPath() are also available. The list of root directories is provided by drives(); on Unix systems this returns a list containing a single root directory, "/"; on Windows the list will usually contain "C:/", and possibly "D:/", etc. It is easiest to work with "/" separators in Qt code. If you need to present a path to the user or need a path in a form suitable for a function in the underlying operating system use convertSeparators(). Example (check if a directory exists): \code QDir dir("example"); if (!dir.exists()) qWarning("Cannot find the example directory"); \endcode (We could also use the static convenience function QFile::exists().) Example (traversing directories and reading a file): \code QDir dir = QDir::root(); // "/" if (!dir.cd("tmp")) { // "/tmp" qWarning("Cannot find the \"/tmp\" directory"); } else { QFile file(dir.filePath("ex1.txt")); // "/tmp/ex1.txt" if (!file.open(QIODevice::ReadWrite)) qWarning("Cannot create the file %s", file.name()); } \endcode A program that lists all the files in the current directory (excluding symbolic links), sorted by size, smallest first: \code #include <QDir> #include <stdio.h> int main(int argc, char *argv[]) { QDir dir; dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); dir.setSorting(QDir::Size | QDir::Reversed); QFileInfoList list = dir.entryInfoList(); printf(" Bytes Filename\n"); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); printf("%10li %s\n", fileInfo.size(), qPrintable(fileInfo.fileName())); } return 0; } \endcode \sa QFileInfo, QFile, QApplication::applicationDirPath()*//*! Constructs a QDir pointing to the given directory \a path. If path is empty the program's working directory, ("."), is used. \sa currentPath()*/QDir::QDir(const QString &path) : d_ptr(new QDirPrivate(this)){ Q_D(QDir); d->setPath(path.isEmpty() ? QString::fromLatin1(".") : path); d->data->nameFilters = QStringList(QString::fromLatin1("*")); d->data->filters = AllEntries; d->data->sort = SortFlags(Name | IgnoreCase);}/*! Constructs a QDir with path \a path, that filters its entries by name using \a nameFilter and by attributes using \a filters. It also sorts the names using \a sort. The default \a nameFilter is an empty string, which excludes nothing; the default \a filters is \l AllEntries, which also means exclude nothing. The default \a sort is \l Name | \l IgnoreCase, i.e. sort by name case-insensitively. If \a path is an empty string, QDir uses "." (the current directory). If \a nameFilter is an empty string, QDir uses the name filter "*" (all files). Note that \a path need not exist. \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting()*/QDir::QDir(const QString &path, const QString &nameFilter, SortFlags sort, Filters filters) : d_ptr(new QDirPrivate(this)){ Q_D(QDir); d->setPath(path.isEmpty() ? QString::fromLatin1(".") : path); d->data->nameFilters = QDir::nameFiltersFromString(nameFilter); bool empty = d->data->nameFilters.isEmpty(); if(!empty) { empty = true; for(int i = 0; i < d->data->nameFilters.size(); ++i) { if(!d->data->nameFilters.at(i).isEmpty()) { empty = false; break; } } } if (empty) d->data->nameFilters = QStringList(QString::fromLatin1("*")); d->data->sort = sort; d->data->filters = filters;}/*! Constructs a QDir object that is a copy of the QDir object for directory \a dir. \sa operator=()*/QDir::QDir(const QDir &dir) : d_ptr(new QDirPrivate(this, &dir)){}/*! Destroys the QDir object frees up its resources. This has no effect on the underlying directory in the file system.*/QDir::~QDir(){ delete d_ptr; d_ptr = 0;}/*! Sets the path of the directory to \a path. The path is cleaned of redundant ".", ".." and of multiple separators. No check is made to see whether a directory with this path actually exists; but you can check for yourself using exists(). The path can be either absolute or relative. Absolute paths begin with the directory separator "/" (optionally preceded by a drive specification under Windows). Relative file names begin with a directory name or a file name and specify a path relative to the current directory. An example of an absolute path is the string "/tmp/quartz", a relative path might look like "src/fatlib". \sa path(), absolutePath(), exists(), cleanPath(), dirName(), absoluteFilePath(), isRelative(), makeAbsolute()*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -