本小节内容主要来自 QDir 类的帮助文档,Qir 类用于访问文件系统中的目录结构和文件等。QDir 类的静态函数通常用于获取程序运行时系统相关的一些路径信息等,而对于具体某一个目录的操作,需要新建 QDir 对象来实现。
QDir 用于操作路径文件名,访问关于目录路径、文件等信息,操作真实的底层文件系统。同时,QDir 的功能对 Qt 程序运行时的内部资源系统也是通用的,内部资源系统以 ":/" 为根目录。
Qt 都是以 '/' 作为统一的路径分隔符,互联网上也是用 '/' 作为 URL 分隔符的。Qt 程序员应当总是使用 '/' 作为路径分隔符,而不用管操作系统原本的路径分隔符是什么。Qt 会自动把自己的路径文件名转换为底层文件系统可接受的形式,从而操作底层文件系统。
QDir 既可以接受相对文件路径,也可以接受绝对文件路径。相对文件路径通常不以文件系统根打头,而绝对路径总是以文件系统根打头,比如 C:/、D:/ 、/ 等等(从这里开始都使用 Qt 默认的路径分隔符)。相对路径的基准目录通常是应用程序的工作路径,比如 QtCreator 调试运行程序时,就以影子构建目录作为基准目录,其他情况通常是以可执行程序所在的目录为准。
绝对路径举例:
QDir("/home/user/Documents")QDir("C:/Documents and Settings")
第一个绝对路径是 Unix/Linux 系统里的形式,第二个绝对路径是 Windows 里的形式。Qt 代码里面都是使用 '/' ,作为路径分隔符,底层文件系统的本地路径分隔符不用操心,交给 Qt 自己处理就行了。
相对路径举例:
QDir("images/landscape.png")
QDir 对象可以通过函数 isRelative() 判断自己包含的路径是否为相对路径,通过函数 isAbsolute() 判断自己包含的路径是否为绝对路径形式。另外可以通过 makeAbsolute() 函数
bool QDir::makeAbsolute()
把自己的路径确切地转换为绝对路径,这样后续操作的意义更为明确。
下面将 QDir 类的接口函数按照功能进行大致的分类讲解:
(1)导航和目录操作
QDir 构造函数可以指定该对象的起始浏览目录:
QDir(const QDir & dir)QDir(const QString & path = QString())QDir(const QString & path, const QString & nameFilter, SortFlags sort = SortFlags( Name | IgnoreCase ), Filters filters = AllEntries)
第一个构造函数是复制另一个 QDir 对象。第二个是以路径字符串构造 QDir 对象,这也是最常用的构造函数,如果参数里字符串是空的,那么就以应用程序当前工作目录 "." 作为起始目录。第三个构造函数可以指定文件名过滤字符串 nameFilter、排序方式 sort ,以及文件类型过滤枚举 filters 。
构造好 QDir 对象之后,就可以获取该对象当前处于的目录:
QString QDir::path() const //可能是相对路径,也可能是绝对路径QString QDir::absolutePath() const //一定返回绝对路径如果要重新设置 QDir 对象的路径,那么可以通过如下函数设置:void QDir::setPath(const QString & path)
注意 setPath() 函数是不检查参数 path 是否存在,也不管是不是有 "./../.." 之类复杂的相对路径形式,所以调用该函数可能进入一个不存在的目录,如果进一步操作可能导致出错,需要在调用该函数之前用 exists() 判断参数里的路径是否存在:
bool QDir::exists(const QString & name) const //参数里既可以判断文件夹,也可以判断文件的存在性bool QDir::exists() const //不带参数,判断 QDir 对象自身路径是否为存在的文件夹,只管文件夹!
第一个带参数的 exists(const QString & name) 函数,既可以判断文件夹的存在性,也可以判断文件的存在性。
第二个只针对 QDir 对象自身路径是否为实际文件夹进行判断,如果 QDir 对象自身路径是一个存在的文件,那么也会返回 false,只有是真实的文件夹 才返回 true。
QDir 对象可以用 dirName() 返回该层级目录的简短名字,不包含路径,通常就是绝对路径的最后一个子串:
QDir("Documents/Letters/Applications").dirName() //返回 "Applications"如果 QDir 构造函数里字符串为空,那么 dirName() 返回当前目录 "." :QDir().dirName() //返回 "."除了 QDir 构造函数和 setPath() 函数,更常用的修改 QDir 对象当前目录位置的函数是 cd():bool QDir::cd(const QString & dirName)
cd() 函数比 setPath() 函数更智能,应该尽量用 cd() 函数,因为 cd() 函数会自动检查参数里的目录是否存在,如果参数里路径不存在,那么该函数返回 false,QDir 对象原本的路径不变;如果切换目录成功就返回 true,并进 入新目录。
QDir 对象有切换到父目录的快捷函数:bool QDir::cdUp()
切换成功就返回 true(有父目录);切换失败就返回 false(没父目录,原本已经到根了)。
QDir对象不仅能访问文件夹,还能在自己当前的目录里面进行创建、重命名和删除的操作:
bool QDir::mkdir(const QString & dirName) const //创建新目录bool QDir::rename(const QString & oldName, const QString & newName) //重命名旧的目录bool QDir::rmdir(const QString & dirName) const //删除一个空目录
这些操作如果成功就返回 true,失败就返回 false。注意:
mkdir() 参数里的文件路径不能是已经有的(创建已有的会返回失败),必须是新的;
rename() 参数里,旧的目录名 oldName 必须存在,新的目录名 newName 不能与已有的重名;
rmdir() 函数只能删除空文件夹,如果文件夹里面有其他文件或子文件夹就不能删除。
操作失败的原因,还有可能是没有权限,因为 Unix/Linux 普通用户经常没有写权限,这些操作就容易失败。对于 Unix/Linux 普通用户,应该只操作自己有写入权限的 /home 路径里面的文件夹和文件。
对于递归创建新的长路径,QDir 提供了快捷函数:
bool QDir::mkpath(const QString & dirPath) const
dirPath 可以是长路径,比如 "/home/suse132/Projects/a/b/c" ,对于路径上已有的文件夹"/home/suse132/",不会构造新的,而后半部不存在的 "Projects/a/b/c" ,该函数会逐级递归创建新文件夹,直到 "/home/suse132/Projects/a/b/c" 每一个层级文件夹都存在。如果创建成功或者 dirPath 已经存在,都会返回 true,创建失败就返回 false。
mkpath() 函数的逆操作函数是:
bool QDir::rmpath(const QString & dirPath) const
注意 rmpath() 只能删除空的文件夹,如果参数里是 "Projects/a/b/c",只要其中有一层的文件夹里面有其他子文件夹或文件,都会操作失败。 而 且不要以绝对路径为参数调用rmpath() 函数,因为文件系统根总是存在的,不能删除,不要这么干!
QDir对象可以对自己目录里的一些属性进行判断,比如:
bool QDir::exists(const QString & name) const //子文件夹或文件是否存在bool QDir::isReadable() const //QDir对象当前目录是否有读权限,Linux系统有些目录普通用户不能读取bool QDir::isAbsolute() const //QDir对象当前目录是否为绝对路径bool QDir::isRelative() const //QDir对象当前目录是否为相对路径bool QDir::isRoot() const //QDir对象当前目录是否为文件系统根一般 QDir 对象会对先前的文件系统状态有个缓存,如果在程序运行时文件系统改变了,可以通过如下函数刷新一下缓存,重新访问文件系统:void QDir::refresh() const
(2)文件和目录内容枚举
目录里面可以包含一大堆条目,每个条目可以是文件、子文件夹、符号链接(快捷方式)等,目录里面的条目计数为:
uint QDir::count() const
如果要获取 QDir 对象当前目录所有子条目名称字符串列表,使用函数:
QStringList QDir::entryList(Filters filters = NoFilter, SortFlags sort = NoSort) constQStringList QDir::entryList(const QStringList & nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) const
函数参数里的 filters 是指条目类型的过滤枚举类型,sort 是指返回的条目列表的排序方式;第二个 entryList() 函数里的 nameFilters 是指条目名称的过滤字符串列表 。这几个参数都有专门对应的设置函数,等会再讲。entryList() 函数返回的字符串列表打印出来就是得到的文件、子文件夹、符号链接(快捷方式)名字。
当前目录里的子条目当然不仅仅有名字,还有其他很多属性,比如文件类型、大小、修改日期、读写属性等等,单个文件或文件夹的详细信息是用 QFileInfo 对象表示的,从 QDir 对象的目录枚举出所有子条目详细信息的函数为:
QFileInfoList QDir::entryInfoList(Filters filters = NoFilter, SortFlags sort = NoSort) constQFileInfoList QDir::entryInfoList(const QStringList & nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) const
entryInfoList() 函数的参数同上面 entryList() 的参数,只是返回结果为 QFileInfo 的列表 QFileInfoList 。QFileInfoList 列表当作数组来用就行了,序号从 0 到 count()-1 ,每个条目对应一个文件或子文件夹或符号链接。
在不过滤的情况下,entryList() 和 entryInfoList() 返回的列表包含 "." 和 ".." 目录,一个点代表当前目录自己,两个点代表父目录。
注意 QDir 对象内部存储的当前目录,可以是真实存在的路径,也可以是虚假的不存在路径:
◆ 实际存在的当前目录通常用于枚举或访问真实子文件夹、文件等,可以用 exists(const QString & name) 函数判断子文件 夹或文件是否存在。
◆ 对于不存在的当前目录,QDir 对象也可以照常工作,但因为不存在,所以枚举子条目肯定是空的。如果 QDir 对象里面存储的是不存在的当前目录,那么通常用于构造路径字符串,用于下一步构建路径,比如用于 mkpath() 函数。
根据 QDir 对象里的当前目录,配合 filePath() 和 absoluteFilePath() 函数可以构造出文件的路径,这些路径可以是都不存在的,也可以是真实的,也是用 exists() 函数判断存在性,以下面代码为例:
QDir directory("Documents/Letters");
QString path = directory.filePath("contents.txt"); QString absolutePath = directory.absoluteFilePath("contents.txt"); qDebug()<如果程序的工作路径(QtCreator调试运行程序时为影子构建目录)为
D:QtProjectsch02build-hellocreator-Desktop_Qt_5_4_0_MinGW_32bit-Debug
实际上在这个路径里,根本没有 "Documents/Letters" 这两级子目录,上面代码还会正常工作,它就是分别计算文件 "contents.txt" 的相对于 QDir 对象的相对路径,以及 "contents.txt" 文件的绝对路径,上面一段代码的结果就是:
false"Documents/Letters/contents.txt""D:/QtProjects/ch02/build-hellocreator-Desktop_Qt_5_4_0_MinGW_32bit-Debug/Documents/Letters/contents.txt"
这些路径其实都不存在,filePath() 和 absoluteFilePath() 函数仅仅是拼接出文件的完整路径,而不管它存在或不存在。
在使用 QDir 对象时,一定要用 exists() 函数谨慎判断路径是否真实存在!
如果要删除一个已存在的文件,使用如下函数:
bool QDir::remove(const QString & fileName)
删除成功就返回 true,如果没有该文件或者没有删除权限等,删除失败返回 false。
删除一个空目录用之前说过的 rmdir() 函数。
下面讲讲枚举子条目时的过滤和排序,除了可以直接在 entryList() 和 entryInfoList() 指定各个参数,还可以用专门的函数设置这两个函数用到的参数:
①名称字符串过滤设置
void QDir::setNameFilters(const QStringList & nameFilters)
nameFilters 是针对子条目名称的过滤串,参考帮助文档主题 QRegExp wildcard matching 的内容,常用的就是 *,匹配任意个数字符,比如
QStringList filters; filters << "*.cpp" << "*.cxx" << "*.cc"; dir.setNameFilters(filters);
这段代码就是过滤后得到 "*.cpp" 、 "*.cxx" 、 "*.cc" 三个扩展名的源代码文件。
QDir 类另外提供了一个静态函数,用于判断某个文件名是否匹配某个名称过滤串:
bool QDir::match(const QString & filter, const QString & fileName) //静态函数
②类型权限等过滤设置
void QDir::setFilter(Filters filters)
这个 filters 与条目名称无关,它判断的是条目类型,Filters 枚举常量很多,根据 QDir 的帮助文档列举如下:
一般对于条目类型,使用默认的不过滤即可,如果确定要过滤为仅文件或仅文件夹,可以用上面的枚举常量进行筛选。QDir::Readable、 QDir::Writable 、QDir::Executable 是 Unix/Linux 系统里常见的权限划分,需要与 QDir::Dirs 或者 QDir::Files 做按位或 | ,结合使用。
③排序设置
void QDir::setSorting(SortFlags sort)
这个参数决定 entryList() 和 entryInfoList() 返回列表的排序方式,SortFlags 排序的枚举常量如下:
注意前四个排序常量只能四选一,不能同时运用。一般在前四个选一个作为排序标准,后面的枚举常量与前面四选一的做 | 运算,后面的枚举常量就可以同时生效。
无论是通过上面三个设置函数专门设置,还是直接在 entryList() 和 entryInfoList() 指定各个参数,都是可行的,效果是等价的。
(3)应用程序工作路径和其他特殊路径
这部分都是 QDir 类的静态函数,属于该应用程序自己的全局设置,这些静态函数返回 QDir 对象或 QString 字符串,列举如下:
其中应用程序自己的工作路径是可以改的:
bool QDir::setCurrent(const QString & path)
其他的路径一般都是系统定死的,Qt 是不修改其他三个路径的。
应用程序的工作路径不等于可执行程序所在的目录,比如 QtCreator 调试运行程序时,工作路径是影子构建目录。获取可执行程序所在的目录使用另一个类的静态函数:
QString QCoreApplication::applicationDirPath() //静态函数
联合 QDir::setCurrent() 和 QCoreApplication::applicationDirPath() 就可以把程序的工作路径设置为与可执行文件相同的路径:
QDir::setCurrent( QCoreApplication::applicationDirPath() ); qDebug()<<:currentpath>
把上面代码放到主界面的构造函数里就能在程序运行时自动修改工作路径。
如果要获取文件系统根的列表,使用 QDir::drives() 静态函数,之前 Windows 和 Linux 文件系统截图都提到这个函数:
QFileInfoList QDir::drives() //静态函数
对于 Windows 系统,一般有多个文件系统根,如 C:/ ,D:/ 等等,对于 Unix 和 Linux 系统,只有一个根 / 。
(4)路径操作和字符串
相对路径中经常包含一些 "." 代表当前目录,".." 代表父目录,还有一些符号链接(快捷方式)指向其他真实文件。
Qt 提供了如下函数对这些进行处理规约,得到绝对权威路径:
QString QDir::canonicalPath() const //会自动判断路径是否真实存在
如果规约后的当前路径是不存在的,那么该函数返回空串,如果规约后的当前路径是真实存在的,就返回最简化的绝对权威路径。
另一个弱化版的静态规约函数是 cleanPath(),它不检查路径是否真实存在,也不管是不是符号链接(快捷方式),它只对 "." 、 ".." "/" 等做规约处理,去掉冗余的点号和斜杠:
QString QDir::cleanPath(const QString & path) //静态函数
在特殊场合,可能需要将 Qt 统一的路径字符串形式与操作系统本地化的文件路径形式进行互相转换,QDir 提供一对静态函数实现这个转换:
QString QDir::fromNativeSeparators(const QString & pathName) //静态函数,从本地化路径串转为 Qt 风格路径串QString QDir::toNativeSeparators(const QString & pathName) //静态函数,将 Qt 风格路径串转为本地化路径串
关于 QDir 类的内容介绍就到这,最后小节的文件浏览示例是用最简单的接口,也不排序和过滤,就按照默认的参数列举文件夹和文件,等到下一章学到表格控件时再做排序和过滤方面的功能。
转载自:https://qtguide.ustclug.org/