原文: http://zetcode.com/gui/qt4/files/

在 Qt4 C++ 编程教程的这一部分中,我们处理文件和目录。

QFileQDirQFileInfo是在 Qt4 中处理文件的基本类。 QFile提供了用于读取和写入文件的接口。 QDir提供对目录结构及其内容的访问。 QFileInfo提供与系统无关的文件信息,包括文件名和在文件系统中的位置,访问时间和修改时间,权限或文件所有权。

文件大小

在下一个示例中,我们确定文件的大小。

file_size.cpp

  1. #include <QTextStream>
  2. #include <QFileInfo>
  3. int main(int argc, char *argv[]) {
  4. QTextStream out(stdout);
  5. if (argc != 2) {
  6. qWarning("Usage: file_size file");
  7. return 1;
  8. }
  9. QString filename = argv[1];
  10. if (!QFile(filename).exists()) {
  11. qWarning("The file does not exist");
  12. return 1;
  13. }
  14. QFileInfo fileinfo(filename);
  15. qint64 size = fileinfo.size();
  16. QString str = "The size is: %1 bytes";
  17. out << str.arg(size) << endl;
  18. }

文件的大小由QFileInfosize()方法确定。

  1. QString filename = argv[1];

文件名作为参数传递给程序。

  1. if (!QFile(filename).exists()) {
  2. qWarning("The file does not exist");
  3. return 1;
  4. }

使用QFile类的exists()方法检查文件的存在。 如果不存在,我们将发出警告并终止程序。

  1. QFileInfo fileinfo(filename);

创建QFileInfo的实例。

  1. qint64 size = fileinfo.size();

文件大小由size()方法确定。 qint64是在 Qt 支持的所有平台上保证为 64 位的类型。

  1. QString str = "The size is: %1 bytes";
  2. out << str.arg(size) << endl;

结果将打印到控制台。

  1. $ ./file_size Makefile
  2. The size is: 7483 bytes

这是示例的输出。

读取文件内容

为了读取文件的内容,我们必须首先打开文件进行读取。 然后创建一个输入文件流; 从该流中读取数据。

read_file.cpp

  1. #include <QTextStream>
  2. #include <QFile>
  3. int main(void) {
  4. QTextStream out(stdout);
  5. QFile file("colours");
  6. if (!file.open(QIODevice::ReadOnly)) {
  7. qWarning("Cannot open file for reading");
  8. return 1;
  9. }
  10. QTextStream in(&file);
  11. while (!in.atEnd()) {
  12. QString line = in.readLine();
  13. out << line << endl;
  14. }
  15. file.close();
  16. }

该示例从colours文件读取数据。 该文件包含八种颜色的名称。

  1. QFile file("colours");

创建QFile对象的实例。

  1. if (!file.open(QIODevice::ReadOnly)) {
  2. qWarning("Cannot open file for reading");
  3. return 1;
  4. }

QFileopen()方法以只读模式打开文件。 如果该方法失败,我们将发出警告并终止程序。

  1. QTextStream in(&file);

创建输入流。 QTextStream接收文件句柄。 将从该流中读取数据。

  1. while (!in.atEnd()) {
  2. QString line = in.readLine();
  3. out << line << endl;
  4. }

while循环中,我们逐行读取文件,直到文件结束。 如果没有更多数据要从流中读取,则atEnd()方法返回truereadLine()方法从流中读取一行。

  1. file.close();

close()方法刷新数据并关闭文件句柄。

  1. $ ./read_file colours
  2. red
  3. green
  4. blue
  5. yellow
  6. brown
  7. white
  8. black
  9. orange

这是示例的输出。

写入文件

为了写入文件,我们在写入模式下打开文件,创建定向到该文件的输出流,并使用写入运算符写入该流。

write2file.cpp

  1. #include <QTextStream>
  2. #include <QFile>
  3. int main(void) {
  4. QTextStream out(stdout);
  5. QString filename = "distros";
  6. QFile file(filename);
  7. if (file.open(QIODevice::WriteOnly)) {
  8. QTextStream out(&file);
  9. out << "Xubuntu" << endl;
  10. out << "Arch" << endl;
  11. out << "Debian" << endl;
  12. out << "Redhat" << endl;
  13. out << "Slackware" << endl;
  14. } else {
  15. qWarning("Could not open file");
  16. }
  17. file.close();
  18. }

该示例将五个 Linux 发行版的名称写入名为distros的文件名。

  1. QString filename = "distros";
  2. QFile file(filename);

使用提供的文件名创建QFile对象。

  1. if (file.open(QIODevice::WriteOnly)) {

使用open()方法,我们以只写方法打开文件。

  1. QTextStream out(&file);

该行创建一个在文件句柄上运行的QTextStream。 换句话说,要写入的数据流被定向到文件。

  1. out << "Xubuntu" << endl;
  2. out << "Arch" << endl;
  3. out << "Debian" << endl;
  4. out << "Redhat" << endl;
  5. out << "Slackware" << endl;

数据通过<<运算符写入。

  1. file.close();

最后,文件句柄被关闭。

  1. $ ./write2file
  2. $ cat distros
  3. Xubuntu
  4. Arch
  5. Debian
  6. Redhat
  7. Slackware

这是示例输出。

复制文件

复制文件时,我们将使用文件名或文件系统的不同位置来精确复制该文件。

copy_file.cpp

  1. #include <QTextStream>
  2. #include <QFile>
  3. int main(int argc, char *argv[]) {
  4. QTextStream out(stdout);
  5. if (argc != 3) {
  6. qWarning("Usage: copyfile source destination");
  7. return 1;
  8. }
  9. QString source = argv[1];
  10. if (!QFile(source).exists()) {
  11. qWarning("The source file does not exist");
  12. return 1;
  13. }
  14. QString destin(argv[2]);
  15. QFile::copy(source, destin);
  16. }

该示例使用QFile::copy()方法创建提供的文件的副本。

  1. if (argc != 3) {
  2. qWarning("Usage: copyfile source destination");
  3. return 1;
  4. }

该程序有两个参数。 如果未给出,则以警告消息结尾。

  1. QString source = argv[1];

从程序的命令行参数中,我们获得源文件的名称。

  1. if (!QFile(source).exists()) {
  2. qWarning("The source file does not exist");
  3. return 1;
  4. }

我们使用QFileexists()方法检查源文件是否存在。 如果它不存在,我们将以警告消息终止该程序。

  1. QString destin(argv[2]);

我们得到目标文件名。

  1. QFile::copy(source, destin);

使用QFile::copy()方法复制源文件。 第一个参数是源文件名,第二个参数是目标文件名。

文件所有者和组

每个文件都有一个拥有者的用户。 文件也属于一组用户,以更好地管理和保护文件。

owner.cpp

  1. #include <QTextStream>
  2. #include <QFileInfo>
  3. int main(int argc, char *argv[]) {
  4. QTextStream out(stdout);
  5. if (argc != 2) {
  6. qWarning("Usage: owner file");
  7. return 1;
  8. }
  9. QString filename = argv[1];
  10. QFileInfo fileinfo(filename);
  11. QString group = fileinfo.group();
  12. QString owner = fileinfo.owner();
  13. out << "Group: " << group << endl;
  14. out << "Owner: " << owner << endl;
  15. }

该示例打印给定文件的所有者和主要组。

  1. QFileInfo fileinfo(filename);

创建QFileInfo类的实例。 它的参数是作为命令行参数给出的文件名。

  1. QString group = fileinfo.group();

文件的主要组是通过QFileInfogroup()方法确定的。

  1. QString owner = fileinfo.owner();

文件的所有者通过QFileInfoowner()方法确定。

  1. $ touch myfile
  2. $ ./owner myfile
  3. Group: janbodnar
  4. Owner: janbodnar

系统会自动为新创建的文件提供用户的默认组。

上次读取,上次修改

文件存储有关上次读取或修改它们的信息。 要获取此信息,我们使用QFileInfo类。

file_times.cpp

  1. #include <QTextStream>
  2. #include <QFileInfo>
  3. #include <QDateTime>
  4. int main(int argc, char *argv[]) {
  5. QTextStream out(stdout);
  6. if (argc != 2) {
  7. qWarning("Usage: file_times file");
  8. return 1;
  9. }
  10. QString filename = argv[1];
  11. QFileInfo fileinfo(filename);
  12. QDateTime last_rea = fileinfo.lastRead();
  13. QDateTime last_mod = fileinfo.lastModified();
  14. out << "Last read: " << last_rea.toString() << endl;
  15. out << "Last modified: " << last_mod.toString() << endl;
  16. }

该示例打印给定文件的最后读取时间和最后修改时间。

  1. QFileInfo fileinfo(filename);

QFileInfo对象已创建。

  1. QDateTime last_rea = fileinfo.lastRead();

lastRead()方法返回上次读取(访问)文件的日期和时间。

  1. QDateTime last_mod = fileinfo.lastModified();

lastModified()方法返回上次修改文件的日期和时间。

  1. $ ./file_times Makefile
  2. Last read: Mon Oct 19 10:23:54 2015
  3. Last modified: Mon Oct 19 10:23:33 2015

时间可以相同也可以不相同。

处理目录

QDir类具有用于处理目录的方法。

dirs.cpp

  1. #include <QTextStream>
  2. #include <QDir>
  3. int main(void) {
  4. QTextStream out(stdout);
  5. QDir dir;
  6. if (dir.mkdir("mydir")) {
  7. out << "mydir successfully created" << endl;
  8. }
  9. dir.mkdir("mydir2");
  10. if (dir.exists("mydir2")) {
  11. dir.rename("mydir2", "newdir");
  12. }
  13. dir.mkpath("temp/newdir");
  14. }

在示例中,我们提供了四种使用目录的方法。

  1. if (dir.mkdir("mydir")) {
  2. out << "mydir successfully created" << endl;
  3. }

mkdir()方法创建一个目录。 如果目录创建成功,则返回true

  1. if (dir.exists("mydir2")) {
  2. dir.rename("mydir2", "newdir");
  3. }

exists()检查目录是否存在。 rename()方法重命名目录。

  1. dir.mkpath("temp/newdir");

mkpath()一键创建一个新目录和所有必要的父目录。

特殊路径

文件系统中有一些特殊的路径。 例如主目录或根目录。 QDir类用于获取系统中的特殊路径。

special_paths.cpp

  1. #include <QTextStream>
  2. #include <QDir>
  3. int main(void) {
  4. QTextStream out(stdout);
  5. out << "Current path:" << QDir::currentPath() << endl;
  6. out << "Home path:" << QDir::homePath() << endl;
  7. out << "Temporary path:" << QDir::tempPath() << endl;
  8. out << "Rooth path:" << QDir::rootPath() << endl;
  9. }

该示例打印四个特殊路径。

  1. out << "Current path:" << QDir::currentPath() << endl;

当前的工作目录使用QDir::currentPath()方法检索。

  1. out << "Home path:" << QDir::homePath() << endl;

使用QDir::homePath()方法返回主目录。

  1. out << "Temporary path:" << QDir::tempPath() << endl;

使用QDir::tempPath()方法检索临时目录。

  1. out << "Rooth path:" << QDir::rootPath() << endl;

根目录通过QDir::rootPath()方法返回。

  1. $ ./special_paths
  2. Current path:/home/janbodnar/prog/qt4/files/special_paths
  3. Home path:/home/janbodnar
  4. Temporary path:/tmp
  5. Rooth path:/

这是一个示例输出。

文件路径

文件由文件名和路径标识。 路径由文件名,基本名和后缀组成。

file_path.cpp

  1. #include <QTextStream>
  2. #include <QFileInfo>
  3. int main(int argc, char *argv[]) {
  4. QTextStream out(stdout);
  5. if (argc != 2) {
  6. out << "Usage: file_times file" << endl;
  7. return 1;
  8. }
  9. QString filename = argv[1];
  10. QFileInfo fileinfo(filename);
  11. QString absPath = fileinfo.absoluteFilePath();
  12. QString baseName = fileinfo.baseName();
  13. QString compBaseName = fileinfo.completeBaseName();
  14. QString fileName = fileinfo.fileName();
  15. QString suffix = fileinfo.suffix();
  16. QString compSuffix = fileinfo.completeSuffix();
  17. out << "Absolute file path: " << absPath << endl;
  18. out << "Base name: " << baseName << endl;
  19. out << "Complete base name: " << compBaseName << endl;
  20. out << "File name: " << fileName << endl;
  21. out << "Suffix: " << suffix << endl;
  22. out << "Whole suffix: " << compSuffix << endl;
  23. }

在示例中,我们使用几种方法来打印文件路径及其给定文件名的一部分。

  1. QFileInfo fileinfo(filename);

文件路径是使用QFileInfo类标识的。

  1. QString absPath = fileinfo.absoluteFilePath();

absoluteFilePath()方法返回包含文件名的绝对路径。

  1. QString baseName = fileinfo.baseName();

baseName()方法返回基本名称-没有路径的文件名称。

  1. QString compBaseName = fileinfo.completeBaseName();

completeBaseName()方法返回完整的基本名称-文件中的所有字符,直到(但不包括)最后一个点字符。

  1. QString fileName = fileinfo.fileName();

fileName()方法返回文件名,该文件名是基本名称和扩展名。

  1. QString suffix = fileinfo.suffix();

suffix()方法返回文件结尾,该结尾由文件中所有字符组成,该文件之后(但不包括)最后一个点字符。

  1. QString compSuffix = fileinfo.completeSuffix();

文件结尾可能由几部分组成。 completeSuffix()方法返回第一个点字符之后(但不包括)后的文件中的所有字符。

  1. $ ./file_path ~/Downloads/qt-everywhere-opensource-src-4.8.7.tar.gz
  2. Absolute file path: /home/janbodnar/Downloads/qt-everywhere-opensource-src-4.8.7.tar.gz
  3. Base name: qt-everywhere-opensource-src-4
  4. Complete base name: qt-everywhere-opensource-src-4.8.7.tar
  5. File name: qt-everywhere-opensource-src-4.8.7.tar.gz
  6. Suffix: gz
  7. Whole suffix: 8.7.tar.gz

这是程序的输出。

权限

文件系统中的文件具有保护系统。 文件带有标志,这些标志确定谁可以访问和修改它们。 QFile::permissions()方法返回有关文件的 OR-ED 标志的枚举。

permissions.cpp

  1. #include <QTextStream>
  2. #include <QFile>
  3. int main(int argc, char *argv[]) {
  4. QTextStream out(stdout);
  5. if (argc != 2) {
  6. out << "Usage: permissions file" << endl;
  7. return 1;
  8. }
  9. QString filename = argv[1];
  10. QFile::Permissions ps = QFile::permissions(filename);
  11. QString fper;
  12. if (ps & QFile::ReadOwner) {
  13. fper.append('r');
  14. } else {
  15. fper.append('-');
  16. }
  17. if (ps & QFile::WriteOwner) {
  18. fper.append('w');
  19. } else {
  20. fper.append('-');
  21. }
  22. if (ps & QFile::ExeOwner) {
  23. fper.append('x');
  24. } else {
  25. fper.append('-');
  26. }
  27. if (ps & QFile::ReadGroup) {
  28. fper.append('r');
  29. } else {
  30. fper.append('-');
  31. }
  32. if (ps & QFile::WriteGroup) {
  33. fper.append('w');
  34. } else {
  35. fper.append('-');
  36. }
  37. if (ps & QFile::ExeGroup) {
  38. fper.append('x');
  39. } else {
  40. fper.append('-');
  41. }
  42. if (ps & QFile::ReadOther) {
  43. fper.append('r');
  44. } else {
  45. fper.append('-');
  46. }
  47. if (ps & QFile::WriteOther) {
  48. fper.append('w');
  49. } else {
  50. fper.append('-');
  51. }
  52. if (ps & QFile::ExeOther) {
  53. fper.append('x');
  54. } else {
  55. fper.append('-');
  56. }
  57. out << fper << endl;
  58. }

该示例为给定文件生成类似 Unix 的权限列表。 有几种可能的用户类型:所有者,文件所属的组以及其余的称为其他用户。 前三个位置属于文件的所有者,后三个位置属于文件的组,后三个字符属于其他字符。 权限共有四种:读取(r),写入或修改(w),执行(x)和无权限(-)。

  1. QFile::Permissions ps = QFile::permissions(filename);

通过QFile::permissions()方法,我们获得了权限标志的枚举。

  1. QString fper;

该字符串是根据给定的权限动态构建的。

  1. if (ps & QFile::ReadOwner) {
  2. fper.append('r');
  3. } else {
  4. fper.append('-');
  5. }

我们使用&运算符确定返回的枚举是否包含QFile::ReadOwner标志。

  1. $ ./permissions Makefile
  2. rw-rw-r--

文件所属的所有者和用户组有权读取和修改文件。 其他用户有权读取该文件。 由于该文件不是可执行文件,因此没有执行该文件的权限。

列出目录内容

在下面的示例中,我们显示给定目录的内容。

list_dir.cpp

  1. #include <QTextStream>
  2. #include <QFileInfo>
  3. #include <QDir>
  4. int main(int argc, char *argv[]) {
  5. QTextStream out(stdout);
  6. if (argc != 2) {
  7. qWarning("Usage: list_dir directory");
  8. return 1;
  9. }
  10. QString directory = argv[1];
  11. QDir dir(directory);
  12. if (!dir.exists()) {
  13. qWarning("The directory does not exist");
  14. return 1;
  15. }
  16. dir.setFilter(QDir::Files | QDir::AllDirs);
  17. dir.setSorting(QDir::Size | QDir::Reversed);
  18. QFileInfoList list = dir.entryInfoList();
  19. int max_size = 0;
  20. foreach (QFileInfo finfo, list) {
  21. QString name = finfo.fileName();
  22. int size = name.size();
  23. if (size > max_size) {
  24. max_size = size;
  25. }
  26. }
  27. int len = max_size + 2;
  28. out << QString("Filename").leftJustified(len).append("Bytes") << endl;
  29. for (int i = 0; i < list.size(); ++i) {
  30. QFileInfo fileInfo = list.at(i);
  31. QString str = fileInfo.fileName().leftJustified(len);
  32. str.append(QString("%1").arg(fileInfo.size()));
  33. out << str << endl;
  34. }
  35. return 0;
  36. }

要列出目录的内容,我们使用QDir类及其entryInfoList()方法。 文件列表按其大小反向排序,并且排列整齐。 有两列; 第一列包含文件名,第二列包含文件大小。

  1. QDir dir(directory);

创建具有给定目录名称的QDir对象。

  1. dir.setFilter(QDir::Files | QDir::AllDirs);

setFilter()方法指定entryInfoList()方法应返回的文件类型。

  1. dir.setSorting(QDir::Size | QDir::Reversed);

setSorting()方法指定entryInfoList()方法使用的排序顺序。

  1. QFileInfoList list = dir.entryInfoList();

entryInfoList()方法返回目录中所有文件和目录的QFileInfo对象的列表,并通过过滤和排序方法进行过滤和排序。 QFileInfoListQList<QFileInfo>的同义词。

  1. foreach (QFileInfo finfo, list) {
  2. QString name = finfo.fileName();
  3. int size = name.size();
  4. if (size > max_size) {
  5. max_size = size;
  6. }
  7. }

我们遍历列表并确定最大文件名大小。 需要此信息来整齐地组织输出。

  1. int len = max_size + 2;

我们在列的长度上再加上两个空格。

  1. out << QString("Filename").leftJustified(len).append("Bytes") << endl;

在这里,我们打印列名。 leftJustified()方法返回给定大小的字符串,该字符串左对齐并在其右边用填充字符(默认为空格)填充。

  1. for (int i = 0; i < list.size(); ++i) {
  2. QFileInfo fileInfo = list.at(i);
  3. QString str = fileInfo.fileName().leftJustified(len);
  4. str.append(QString("%1").arg(fileInfo.size()));
  5. out << str << endl;
  6. }

我们浏览文件列表并打印它们的名称和大小。 第一列保持对齐,并在必要时用空格填充; 仅将第二列添加到该行的末尾。

  1. $ ./list_dir .
  2. Filename Bytes
  3. list_dir.pro 302
  4. list_dir.cpp 1092
  5. .. 4096
  6. . 4096
  7. Makefile 7456
  8. list_dir.o 8848
  9. list_dir 14687

这是示例的示例输出。

在本章中,我们使用文件和目录。