ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 在 Qt5 中处理文件和目录 > 原文: [http://zetcode.com/gui/qt5/files/](http://zetcode.com/gui/qt5/files/) 在 Qt5 C++ 编程教程的这一部分中,我们处理文件和目录。 `QFile`,`QDir`和`QFileInfo`是在 Qt5 中处理文件的基本类。 `QFile`提供了用于读取和写入文件的接口。 `QDir`提供对目录结构及其内容的访问。 `QFileInfo`提供与系统无关的文件信息,包括文件名和在文件系统中的位置,访问时间和修改时间,权限或文件所有权。 ## 文件大小 在下一个示例中,我们确定文件的大小。 `file_size.cpp` ```cpp #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()`方法确定。 ```cpp QString filename = argv[1]; ``` 文件名作为参数传递给程序。 ```cpp if (!QFile(filename).exists()) { qWarning("The file does not exist"); return 1; } ``` 使用`QFile`类的`exists()`方法检查文件的存在。 如果不存在,我们将发出警告并终止程序。 ```cpp QFileInfo fileinfo(filename); ``` 创建`QFileInfo`的实例。 ```cpp qint64 size = fileinfo.size(); ``` 文件大小由`size()`方法确定。 `qint64`是在 Qt 支持的所有平台上保证为 64 位的类型。 ```cpp QString str = "The size is: %1 bytes"; out << str.arg(size) << endl; ``` 结果将打印到控制台。 输出: ```cpp $ ./file_size Makefile The size is: 28029 bytes ``` ## 读取文件内容 为了读取文件的内容,我们必须首先打开文件进行读取。 然后创建一个输入文件流; 从该流中读取数据。 `read_file.cpp` ```cpp #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`文件读取数据。 该文件包含八种颜色的名称。 ```cpp QFile file("colours"); ``` 创建`QFile`对象的实例。 ```cpp if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading"); return 1; } ``` `QFile`的`open()`方法以只读模式打开文件。 如果该方法失败,我们将发出警告并终止程序。 ```cpp QTextStream in(&file); ``` 创建输入流。 `QTextStream`接收文件句柄。 将从该流中读取数据。 ```cpp while (!in.atEnd()) { QString line = in.readLine(); out << line << endl; } ``` 在`while`循环中,我们逐行读取文件,直到文件结束。 如果没有更多数据要从流中读取,则`atEnd()`方法返回`true`。 `readLine()`方法从流中读取一行。 ```cpp file.close(); ``` `close()`方法刷新数据并关闭文件句柄。 输出: ```cpp $ ./read_file colours red green blue yellow brown white black violet ``` ## 写入文件 为了写入文件,我们在写入模式下打开文件,创建定向到该文件的输出流,并使用写入运算符写入该流。 `write2file.cpp` ```cpp #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`的文件名。 ```cpp QString filename = "distros"; QFile file(filename); ``` 使用提供的文件名创建`QFile`对象。 ```cpp if (file.open(QIODevice::WriteOnly)) { ``` 使用`open()`方法,我们以只写方法打开文件。 ```cpp QTextStream out(&file); ``` 该行创建一个在文件句柄上运行的`QTextStream`。 换句话说,要写入的数据流被定向到文件。 ```cpp out << "Xubuntu" << endl; out << "Arch" << endl; out << "Debian" << endl; out << "Redhat" << endl; out << "Slackware" << endl; ``` 数据通过`<<`运算符写入。 ```cpp file.close(); ``` 最后,文件句柄被关闭。 输出: ```cpp $ ./write2file $ cat distros Xubuntu Arch Debian Redhat Slackware ``` ## 复制文件 复制文件时,我们将使用文件名或文件系统的不同位置来精确复制该文件。 `copy_file.cpp` ```cpp #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()`方法创建提供的文件的副本。 ```cpp if (argc != 3) { qWarning("Usage: copyfile source destination"); return 1; } ``` 该程序有两个参数。 如果未给出,则以警告消息结尾。 ```cpp QString source = argv[1]; ``` 从程序的命令行参数中,我们获得源文件的名称。 ```cpp if (!QFile(source).exists()) { qWarning("The source file does not exist"); return 1; } ``` 我们使用`QFile`的`exists()`方法检查源文件是否存在。 如果它不存在,我们将以警告消息终止该程序。 ```cpp QString destin(argv[2]); ``` 我们得到目标文件名。 ```cpp QFile::copy(source, destin); ``` 使用`QFile::copy()`方法复制源文件。 第一个参数是源文件名,第二个参数是目标文件名。 ## 文件所有者和组 每个文件都有一个拥有者的用户。 文件也属于一组用户,以更好地管理和保护文件。 `owner.cpp` ```cpp #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; } ``` 该示例打印给定文件的所有者和主要组。 ```cpp QFileInfo fileinfo(filename); ``` 创建`QFileInfo`类的实例。 它的参数是作为命令行参数给出的文件名。 ```cpp QString group = fileinfo.group(); ``` 文件的主要组是通过`QFileInfo`的`group()`方法确定的。 ```cpp QString owner = fileinfo.owner(); ``` 文件的所有者通过`QFileInfo`的`owner()`方法确定。 输出: ```cpp $ touch myfile $ ./owner myfile Group: janbodnar Owner: janbodnar ``` ## 上次读取,上次修改 文件存储有关上次读取或修改它们的信息。 要获取此信息,我们使用`QFileInfo`类。 `file_times.cpp` ```cpp #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; } ``` 该示例打印给定文件的最后读取时间和最后修改时间。 ```cpp QFileInfo fileinfo(filename); ``` `QFileInfo`对象已创建。 ```cpp QDateTime last_rea = fileinfo.lastRead(); ``` `lastRead()`方法返回上次读取(访问)文件的日期和时间。 ```cpp QDateTime last_mod = fileinfo.lastModified(); ``` `lastModified()`方法返回上次修改文件的日期和时间。 输出: ```cpp $ ./file_times Makefile Last read: Sun Nov 1 17:54:31 2015 Last modified: Sun Nov 1 17:54:30 2015 ``` ## 处理目录 `QDir`类具有用于处理目录的方法。 `dirs.cpp` ```cpp #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"); } ``` 在示例中,我们提供了四种使用目录的方法。 ```cpp if (dir.mkdir("mydir")) { out << "mydir successfully created" << endl; } ``` `mkdir()`方法创建一个目录。 如果目录创建成功,则返回`true`。 ```cpp if (dir.exists("mydir2")) { dir.rename("mydir2", "newdir"); } ``` `exists()`检查目录是否存在。 `rename()`方法重命名目录。 ```cpp dir.mkpath("temp/newdir"); ``` `mkpath()`一键创建一个新目录和所有必要的父目录。 ## 特殊路径 文件系统中有一些特殊的路径。 例如主目录或根目录。 `QDir`类用于获取系统中的特殊路径。 `special_paths.cpp` ```cpp #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; } ``` 该示例打印四个特殊路径。 ```cpp out << "Current path:" << QDir::currentPath() << endl; ``` 当前的工作目录使用`QDir::currentPath()`方法检索。 ```cpp out << "Home path:" << QDir::homePath() << endl; ``` 使用`QDir::homePath()`方法返回主目录。 ```cpp out << "Temporary path:" << QDir::tempPath() << endl; ``` 使用`QDir::tempPath()`方法检索临时目录。 ```cpp out << "Rooth path:" << QDir::rootPath() << endl; ``` 根目录通过`QDir::rootPath()`方法返回。 输出: ```cpp $ ./special_paths Current path:/home/janbodnar/prog/qt4/files/special_paths Home path:/home/janbodnar Temporary path:/tmp Rooth path:/ ``` ## 文件路径 文件由文件名和路径标识。 路径由文件名,基本名和后缀组成。 `file_path.cpp` ```cpp #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; } ``` 在示例中,我们使用几种方法来打印文件路径及其给定文件名的一部分。 ```cpp QFileInfo fileinfo(filename); ``` 文件路径是使用`QFileInfo`类标识的。 ```cpp QString absPath = fileinfo.absoluteFilePath(); ``` `absoluteFilePath()`方法返回包含文件名的绝对路径。 ```cpp QString baseName = fileinfo.baseName(); ``` `baseName()`方法返回基本名称-没有路径的文件名称。 ```cpp QString compBaseName = fileinfo.completeBaseName(); ``` `completeBaseName()`方法返回完整的基本名称-文件中的所有字符,直到(但不包括)最后一个点字符。 ```cpp QString fileName = fileinfo.fileName(); ``` `fileName()`方法返回文件名,该文件名是基本名称和扩展名。 ```cpp QString suffix = fileinfo.suffix(); ``` `suffix()`方法返回文件结尾,该结尾由文件中所有字符组成,该文件之后(但不包括)最后一个点字符。 ```cpp QString compSuffix = fileinfo.completeSuffix(); ``` 文件结尾可能由几部分组成。 `completeSuffix()`方法返回第一个点字符之后(但不包括)后的文件中的所有字符。 输出: ```cpp $ ./file_path ~/Downloads/qt-everywhere-opensource-src-5.5.1.tar.gz Absolute file path: /home/janbodnar/Downloads/qt-everywhere-opensource-src-5.5.1.tar.gz Base name: qt-everywhere-opensource-src-5 Complete base name: qt-everywhere-opensource-src-5.5.1.tar File name: qt-everywhere-opensource-src-5.5.1.tar.gz Suffix: gz Whole suffix: 5.1.tar.gz ``` ## 权限 文件系统中的文件具有保护系统。 文件带有标志,这些标志确定谁可以访问和修改它们。 `QFile::permissions()`方法返回有关文件的 OR-ED 标志的枚举。 `permissions.cpp` ```cpp #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`)和无权限(`-`)。 ```cpp QFile::Permissions ps = QFile::permissions(filename); ``` 通过`QFile::permissions()`方法,我们获得了权限标志的枚举。 ```cpp QString fper; ``` 该字符串是根据给定的权限动态构建的。 ```cpp if (ps & QFile::ReadOwner) { fper.append('r'); } else { fper.append('-'); } ``` 我们使用&运算符确定返回的枚举是否包含`QFile::ReadOwner`标志。 输出: ```cpp $ ./permissions Makefile rw-rw-r-- ``` 文件所属的所有者和用户组有权读取和修改文件。 其他用户有权读取该文件。 由于该文件不是可执行文件,因此没有执行该文件的权限。 ## 列出目录内容 在下面的示例中,我们显示给定目录的内容。 `list_dir.cpp` ```cpp #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()`方法。 文件列表按其大小反向排序,并且排列整齐。 有两列; 第一列包含文件名,第二列包含文件大小。 ```cpp QDir dir(directory); ``` 创建具有给定目录名称的`QDir`对象。 ```cpp dir.setFilter(QDir::Files | QDir::AllDirs); ``` `setFilter()`方法指定`entryInfoList()`方法应返回的文件类型。 ```cpp dir.setSorting(QDir::Size | QDir::Reversed); ``` `setSorting()`方法指定`entryInfoList()`方法使用的排序顺序。 ```cpp QFileInfoList list = dir.entryInfoList(); ``` `entryInfoList()`方法返回目录中所有文件和目录的`QFileInfo`对象的列表,并通过过滤和排序方法进行过滤和排序。 `QFileInfoList`是`QList<QFileInfo>`的同义词。 ```cpp foreach (QFileInfo finfo, list) { QString name = finfo.fileName(); int size = name.size(); if (size > max_size) { max_size = size; } } ``` 我们遍历列表并确定最大文件名大小。 需要此信息来整齐地组织输出。 ```cpp int len = max_size + 2; ``` 我们在列的长度上再加上两个空格。 ```cpp out << QString("Filename").leftJustified(len).append("Bytes") << endl; ``` 在这里,我们打印列名。 `leftJustified()`方法返回给定大小的字符串,该字符串左对齐并在其右边用填充字符(默认为空格)填充。 ```cpp 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; } ``` 我们浏览文件列表并打印它们的名称和大小。 第一列保持对齐,并在必要时用空格填充; 仅将第二列添加到该行的末尾。 输出: ```cpp $ ./list_dir . Filename Bytes list_dir.pro 291 list_dir.cpp 1092 .. 4096 . 4096 list_dir.o 10440 list_dir 19075 Makefile 28369 ``` 这是示例的示例输出。 在本章中,我们使用文件和目录。