在 Qt4 中使用文件和目录
最后修改于 2023 年 10 月 18 日
在本 Qt4 C++ 编程教程中,我们将使用文件和目录。
QFile
、QDir
和 QFileInfo
是在 Qt4 中使用文件的基本类。QFile
提供了用于从文件读取和写入文件的接口。QDir
提供了对目录结构及其内容的访问。QFileInfo
提供了与系统无关的文件信息,包括文件名和在文件系统中的位置、访问时间和修改时间、权限或文件所有权。
文件大小
在下一个示例中,我们将确定文件的大小。
#include <QTextStream> #include <QFileInfo> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { qWarning("Usage: file_size file"); return 1; } QString filename = argv[1]; if (!QFile(filename).exists()) { qWarning("The file does not exist"); return 1; } QFileInfo fileinfo(filename); qint64 size = fileinfo.size(); QString str = "The size is: %1 bytes"; out << str.arg(size) << endl; }
文件的大小由 QFileInfo
的 size
方法确定。
QString filename = argv[1];
文件名作为参数传递给程序。
if (!QFile(filename).exists()) { qWarning("The file does not exist"); return 1; }
文件的存在性由 QFile
类的 exists
方法检查。如果它不存在,我们会发出警告并终止程序。
QFileInfo fileinfo(filename);
创建一个 QFileInfo
的实例。
qint64 size = fileinfo.size();
文件大小由 size
方法确定。qint64
是一种保证在 Qt 支持的所有平台上都是 64 位的类型。
QString str = "The size is: %1 bytes"; out << str.arg(size) << endl;
结果将打印到控制台。
$ ./file_size Makefile The size is: 7483 bytes
这是示例的输出。
读取文件内容
为了读取文件的内容,我们首先必须以读取模式打开文件。然后创建一个输入文件流;从这个流中,数据被读取。
#include <QTextStream> #include <QFile> int main(void) { QTextStream out(stdout); QFile file("colours"); if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading"); return 1; } QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); out << line << endl; } file.close(); }
该示例从 colours
文件中读取数据。该文件包含八种颜色的名称。
QFile file("colours");
创建一个 QFile
对象的实例。
if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading"); return 1; }
QFile
的 open
方法以只读模式打开文件。如果该方法失败,我们会发出警告并终止程序。
QTextStream in(&file);
创建一个输入流。QTextStream
接收文件句柄。数据将从该流中读取。
while (!in.atEnd()) { QString line = in.readLine(); out << line << endl; }
在 while 循环中,我们逐行读取文件,直到文件末尾。如果流中没有更多数据要读取,atEnd
方法将返回 true。readLine
方法从流中读取一行。
file.close();
close
方法刷新数据并关闭文件句柄。
$ ./read_file colours red green blue yellow brown white black orange
这是示例的输出。
写入文件
为了写入文件,我们以写入模式打开文件,创建一个指向该文件的输出流,并使用写入运算符写入该流。
#include <QTextStream> #include <QFile> int main(void) { QTextStream out(stdout); QString filename = "distros"; QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream out(&file); out << "Xubuntu" << endl; out << "Arch" << endl; out << "Debian" << endl; out << "Redhat" << endl; out << "Slackware" << endl; } else { qWarning("Could not open file"); } file.close(); }
该示例将五个 Linux 发行版的名称写入名为 distros
的文件。
QString filename = "distros"; QFile file(filename);
使用提供的文件名创建 QFile
对象。
if (file.open(QIODevice::WriteOnly)) {
使用 open
方法,我们以只写模式打开文件。
QTextStream out(&file);
这行代码创建一个 QTextStream
,它操作文件句柄。换句话说,要写入的数据流将指向该文件。
out << "Xubuntu" << endl; out << "Arch" << endl; out << "Debian" << endl; out << "Redhat" << endl; out << "Slackware" << endl;
数据使用 << 运算符写入。
file.close();
最后,文件句柄被关闭。
$ ./write2file $ cat distros Xubuntu Arch Debian Redhat Slackware
这是示例输出。
复制文件
当我们复制文件时,我们会创建一个具有不同名称或在文件系统中不同位置的文件的精确副本。
#include <QTextStream> #include <QFile> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 3) { qWarning("Usage: copyfile source destination"); return 1; } QString source = argv[1]; if (!QFile(source).exists()) { qWarning("The source file does not exist"); return 1; } QString destin(argv[2]); QFile::copy(source, destin); }
该示例使用 QFile::copy
方法创建所提供文件的副本。
if (argc != 3) { qWarning("Usage: copyfile source destination"); return 1; }
程序接受两个参数;如果未给出这些参数,它将以警告消息结束。
QString source = argv[1];
从程序的命令行参数中,我们获取源文件的名称。
if (!QFile(source).exists()) { qWarning("The source file does not exist"); return 1; }
我们使用 QFile
的 exists
方法检查源文件的存在性。如果它不存在,我们使用警告消息终止程序。
QString destin(argv[2]);
我们获取目标文件名。
QFile::copy(source, destin);
源文件使用 QFile::copy
方法复制。第一个参数是源文件名,第二个参数是目标文件名。
文件所有者和组
每个文件都有一个用户,该用户是它的所有者。一个文件也属于一组用户,以便更好地管理和保护文件。
#include <QTextStream> #include <QFileInfo> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { qWarning("Usage: owner file"); return 1; } QString filename = argv[1]; QFileInfo fileinfo(filename); QString group = fileinfo.group(); QString owner = fileinfo.owner(); out << "Group: " << group << endl; out << "Owner: " << owner << endl; }
该示例打印给定文件的所有者和主组。
QFileInfo fileinfo(filename);
创建一个 QFileInfo
类的实例。它的参数是作为命令行参数给出的文件名。
QString group = fileinfo.group();
文件的主组由 QFileInfo
的 group
方法确定。
QString owner = fileinfo.owner();
文件的所有者由 QFileInfo
的 owner
方法确定。
$ touch myfile $ ./owner myfile Group: janbodnar Owner: janbodnar
新创建的文件会自动获得用户默认组。
最后读取,最后修改
文件存储有关上次读取或修改它们的时间的信息。要获取此信息,我们使用 QFileInfo
类。
#include <QTextStream> #include <QFileInfo> #include <QDateTime> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { qWarning("Usage: file_times file"); return 1; } QString filename = argv[1]; QFileInfo fileinfo(filename); QDateTime last_rea = fileinfo.lastRead(); QDateTime last_mod = fileinfo.lastModified(); out << "Last read: " << last_rea.toString() << endl; out << "Last modified: " << last_mod.toString() << endl; }
该示例打印给定文件的最后读取和最后修改时间。
QFileInfo fileinfo(filename);
创建 QFileInfo
对象。
QDateTime last_rea = fileinfo.lastRead();
lastRead
方法返回文件上次读取(访问)的日期和时间。
QDateTime last_mod = fileinfo.lastModified();
lastModified
方法返回文件上次修改的日期和时间。
$ ./file_times Makefile Last read: Mon Oct 19 10:23:54 2015 Last modified: Mon Oct 19 10:23:33 2015
时间可能不同,也可能相同。
使用目录
QDir
类具有用于处理目录的方法。
#include <QTextStream> #include <QDir> int main(void) { QTextStream out(stdout); QDir dir; if (dir.mkdir("mydir")) { out << "mydir successfully created" << endl; } dir.mkdir("mydir2"); if (dir.exists("mydir2")) { dir.rename("mydir2", "newdir"); } dir.mkpath("temp/newdir"); }
在这个例子中,我们介绍了四种处理目录的方法。
if (dir.mkdir("mydir")) { out << "mydir successfully created" << endl; }
mkdir
方法创建一个目录。如果目录创建成功,它将返回 true。
if (dir.exists("mydir2")) { dir.rename("mydir2", "newdir"); }
exists
检查目录是否存在。rename
方法重命名目录。
dir.mkpath("temp/newdir");
mkpath
一次创建一个新目录和所有必要的父目录。
特殊路径
文件系统中存在一些特殊路径;例如,一个主目录或一个根目录。QDir
类用于获取系统中的特殊路径。
#include <QTextStream> #include <QDir> int main(void) { QTextStream out(stdout); out << "Current path:" << QDir::currentPath() << endl; out << "Home path:" << QDir::homePath() << endl; out << "Temporary path:" << QDir::tempPath() << endl; out << "Rooth path:" << QDir::rootPath() << endl; }
该示例打印了四个特殊路径。
out << "Current path:" << QDir::currentPath() << endl;
当前工作目录使用 QDir::currentPath
方法检索。
out << "Home path:" << QDir::homePath() << endl;
主目录使用 QDir::homePath
方法返回。
out << "Temporary path:" << QDir::tempPath() << endl;
临时目录使用 QDir::tempPath
方法检索。
out << "Rooth path:" << QDir::rootPath() << endl;
根目录由 QDir::rootPath
方法返回。
$ ./special_paths Current path:/home/janbodnar/prog/qt4/files/special_paths Home path:/home/janbodnar Temporary path:/tmp Rooth path:/
这是一个示例输出。
文件路径
文件由其名称和路径标识;路径由文件名、基本名称和后缀组成。
#include <QTextStream> #include <QFileInfo> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { out << "Usage: file_times file" << endl; return 1; } QString filename = argv[1]; QFileInfo fileinfo(filename); QString absPath = fileinfo.absoluteFilePath(); QString baseName = fileinfo.baseName(); QString compBaseName = fileinfo.completeBaseName(); QString fileName = fileinfo.fileName(); QString suffix = fileinfo.suffix(); QString compSuffix = fileinfo.completeSuffix(); out << "Absolute file path: " << absPath << endl; out << "Base name: " << baseName << endl; out << "Complete base name: " << compBaseName << endl; out << "File name: " << fileName << endl; out << "Suffix: " << suffix << endl; out << "Whole suffix: " << compSuffix << endl; }
在这个例子中,我们使用几种方法来打印文件路径及其给定文件名的各个部分。
QFileInfo fileinfo(filename);
文件路径使用 QFileInfo
类标识。
QString absPath = fileinfo.absoluteFilePath();
absoluteFilePath
方法返回一个绝对路径,包括文件名。
QString baseName = fileinfo.baseName();
baseName
方法返回基本名称 - 不带路径的文件名。
QString compBaseName = fileinfo.completeBaseName();
completeBaseName
方法返回完整的基本名称 - 文件中直到(但不包括)最后一个点字符的所有字符。
QString fileName = fileinfo.fileName();
fileName
方法返回文件名,即基本名称和扩展名。
QString suffix = fileinfo.suffix();
suffix
方法返回文件结尾,它由文件中最后一个点字符之后(但不包括)的所有字符组成。
QString compSuffix = fileinfo.completeSuffix();
文件结尾可以由几个部分组成;completeSuffix
方法返回文件中第一个点字符之后(但不包括)的所有字符。
$ ./file_path ~/Downloads/qt-everywhere-opensource-src-4.8.7.tar.gz Absolute file path: /home/janbodnar/Downloads/qt-everywhere-opensource-src-4.8.7.tar.gz Base name: qt-everywhere-opensource-src-4 Complete base name: qt-everywhere-opensource-src-4.8.7.tar File name: qt-everywhere-opensource-src-4.8.7.tar.gz Suffix: gz Whole suffix: 8.7.tar.gz
这是程序的输出。
权限
文件系统中的文件具有保护系统。文件被赋予标志,这些标志决定了谁可以访问和修改它们。QFile::permissions
方法返回相关文件的 OR-ed 标志的枚举。
#include <QTextStream> #include <QFile> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { out << "Usage: permissions file" << endl; return 1; } QString filename = argv[1]; QFile::Permissions ps = QFile::permissions(filename); QString fper; if (ps & QFile::ReadOwner) { fper.append('r'); } else { fper.append('-'); } if (ps & QFile::WriteOwner) { fper.append('w'); } else { fper.append('-'); } if (ps & QFile::ExeOwner) { fper.append('x'); } else { fper.append('-'); } if (ps & QFile::ReadGroup) { fper.append('r'); } else { fper.append('-'); } if (ps & QFile::WriteGroup) { fper.append('w'); } else { fper.append('-'); } if (ps & QFile::ExeGroup) { fper.append('x'); } else { fper.append('-'); } if (ps & QFile::ReadOther) { fper.append('r'); } else { fper.append('-'); } if (ps & QFile::WriteOther) { fper.append('w'); } else { fper.append('-'); } if (ps & QFile::ExeOther) { fper.append('x'); } else { fper.append('-'); } out << fper << endl; }
该示例为给定文件生成类似 Unix 的权限列表。有三种可能的用户:所有者、文件所属的组和其他用户。前三个位置属于文件的所有者,接下来的三个位置属于文件的组,最后三个字符属于其他人。有四种权限:读取 (r)、写入或修改 (w)、执行 (x) 和无权限 (-)。
QFile::Permissions ps = QFile::permissions(filename);
使用 QFile::permissions
方法,我们获得权限标志的枚举。
QString fper;
这个字符串是根据给定的权限动态构建的。
if (ps & QFile::ReadOwner) { fper.append('r'); } else { fper.append('-'); }
我们使用 & 运算符来确定返回的枚举是否包含 QFile::ReadOwner
标志。
$ ./permissions Makefile rw-rw-r--
文件所属的所有者和用户组有权读取和修改文件。其他用户有权读取文件。由于该文件不是可执行文件,因此没有执行文件的权限。
列出目录内容
在下面的示例中,我们显示了给定目录的内容。
#include <QTextStream> #include <QFileInfo> #include <QDir> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { qWarning("Usage: list_dir directory"); return 1; } QString directory = argv[1]; QDir dir(directory); if (!dir.exists()) { qWarning("The directory does not exist"); return 1; } dir.setFilter(QDir::Files | QDir::AllDirs); dir.setSorting(QDir::Size | QDir::Reversed); QFileInfoList list = dir.entryInfoList(); int max_size = 0; foreach (QFileInfo finfo, list) { QString name = finfo.fileName(); int size = name.size(); if (size > max_size) { max_size = size; } } int len = max_size + 2; out << QString("Filename").leftJustified(len).append("Bytes") << endl; for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); QString str = fileInfo.fileName().leftJustified(len); str.append(QString("%1").arg(fileInfo.size())); out << str << endl; } return 0; }
要列出目录的内容,我们使用 QDir
类及其 entryInfoList
方法。文件列表按其大小进行反向排序并整齐地排列。有两列;第一列包含文件名,第二列包含文件大小。
QDir dir(directory);
创建一个带有给定目录名称的 QDir
对象。
dir.setFilter(QDir::Files | QDir::AllDirs);
setFilter
方法指定 entryInfoList
方法应返回的文件类型。
dir.setSorting(QDir::Size | QDir::Reversed);
setSorting
方法指定 entryInfoList
方法使用的排序顺序。
QFileInfoList list = dir.entryInfoList();
entryInfoList
方法返回目录中所有文件和目录的 QFileInfo
对象列表,这些对象由过滤和排序方法进行过滤和排序。QFileInfoList
是 QList<QFileInfo>
的同义词。
foreach (QFileInfo finfo, list) { QString name = finfo.fileName(); int size = name.size(); if (size > max_size) { max_size = size; } }
我们遍历列表并确定最大文件名大小。此信息对于整齐地组织输出是必需的。
int len = max_size + 2;
我们给该列的长度增加了两个空格。
out << QString("Filename").leftJustified(len).append("Bytes") << endl;
在这里我们打印列名。leftJustified
方法返回给定大小的字符串,其字符串向左对齐并用填充字符(默认为空格)填充到右侧。
for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); QString str = fileInfo.fileName().leftJustified(len); str.append(QString("%1").arg(fileInfo.size())); out << str << endl; }
我们遍历文件列表并打印它们的文件名和大小。第一列向左对齐,并根据需要用空格填充;第二列只是附加到该行的末尾。
$ ./list_dir . Filename Bytes list_dir.pro 302 list_dir.cpp 1092 .. 4096 . 4096 Makefile 7456 list_dir.o 8848 list_dir 14687
这是该示例的示例输出。
在本章中,我们使用了文件和目录。