在 Qt4 中使用文件和目录
在 Qt4 C++ 编程教程的这一部分中,我们处理文件和目录。
QFile
,QDir
和QFileInfo
是在 Qt4 中处理文件的基本类。 QFile
提供了用于读取和写入文件的接口。 QDir
提供对目录结构及其内容的访问。 QFileInfo
提供与系统无关的文件信息,包括文件名和在文件系统中的位置,访问时间和修改时间,权限或文件所有权。
文件大小
在下一个示例中,我们确定文件的大小。
file_size.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()
方法确定。
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
这是示例的输出。
读取文件内容
为了读取文件的内容,我们必须首先打开文件进行读取。 然后创建一个输入文件流; 从该流中读取数据。
read_file.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
文件读取数据。 该文件包含八种颜色的名称。
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
这是示例的输出。
写入文件
为了写入文件,我们在写入模式下打开文件,创建定向到该文件的输出流,并使用写入运算符写入该流。
write2file.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
的文件名。
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
这是示例输出。
复制文件
复制文件时,我们将使用文件名或文件系统的不同位置来精确复制该文件。
copy_file.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()
方法创建提供的文件的副本。
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()
方法复制源文件。 第一个参数是源文件名,第二个参数是目标文件名。
文件所有者和组
每个文件都有一个拥有者的用户。 文件也属于一组用户,以更好地管理和保护文件。
owner.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;
}
该示例打印给定文件的所有者和主要组。
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
类。
file_times.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;
}
该示例打印给定文件的最后读取时间和最后修改时间。
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
类具有用于处理目录的方法。
dirs.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");
}
在示例中,我们提供了四种使用目录的方法。
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
类用于获取系统中的特殊路径。
special_paths.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;
}
该示例打印四个特殊路径。
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:/
这是一个示例输出。
文件路径
文件由文件名和路径标识。 路径由文件名,基本名和后缀组成。
file_path.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;
}
在示例中,我们使用几种方法来打印文件路径及其给定文件名的一部分。
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 标志的枚举。
permissions.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
)和无权限(-
)。
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--
文件所属的所有者和用户组有权读取和修改文件。 其他用户有权读取该文件。 由于该文件不是可执行文件,因此没有执行该文件的权限。
列出目录内容
在下面的示例中,我们显示给定目录的内容。
list_dir.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()
方法。 文件列表按其大小反向排序,并且排列整齐。 有两列; 第一列包含文件名,第二列包含文件大小。
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
这是示例的示例输出。
在本章中,我们使用文件和目录。