
点击上方蓝字关注我们


实际开发中,几乎所有的应用程序都要在文件系统中进行文件访问和读写操作,在学习复杂的应用程序之前,必须先扎实地学好文件操作相关的类。Qt中涉及文件操作的类比较多,本章节主要重点介绍最常用的一些类。
6.1 QDir目录操作 QDir类提供了访问目录结构和文件的方法。QDir 用于操作路径文件名,访问关于目录路径、文件等信息,操作真实的底层文件系统。它也可以用来访问Qt的资源系统,内部资源系统以 ":/" 为根目录。Qt使用“/”作为一个通用的目录分隔符,Qurl网址格式也是以同样的方式作为路径分隔符。编写程序时应该全部使用“/”作为目录分隔符,Qt会自动把自己的路径文件名转换为底层文件系统可接受的形式,从而操作底层文件系统。QDir支持相对文件路径和绝对文件路径访问。相对路径的基准目录通常是应用程序的工作路径,就是应用程序运行的目录。
1. Linux系统与Windows系统下绝对路径的表示方法示例
QDir("/home/user/Documents")
QDir("C:/Documents and Settings")
|
2. 相对路径的表示方法示例
QDir("images/landscape.png")
|
6.1.1 遍历指定目录下的所有文件和目录 #include <QApplication>
#include <QDir>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDir dir("D:/"); //构造目录
QStringList infolist = dir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries);
for(int i=0; i<infolist.size(); i++)
qDebug() << infolist.at(i); //打印出所有的信息
return a.exec();
}
|
6.1.2 函数介绍 1. 构造目录对象
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的路径。
第二个构造函数可以直接传入路径字符串,传入的路径可能是无效路径,需要注意检查。
第三个构造函数可以指定需要过滤的文件名字符串nameFilter、排序方式 sort ,以及过滤的文件类型枚举filters。
2. 检查目录或者文件是否存在
booQDir::exists() const
booQDir::exists(const QString &name) const
|
第一个不带参数的exists()函数,用于检查当前QDir包含的目录是否存在,目录存在将返回true。
第二个带参数的exists()函数,可以传入指定的目录和文件名,判断目录或者文件名是否存在,存在将返回true。
示例:
QDir dir("C:/Windows/"); //构造目录
qDebug()<<dir.exists(); //如果QDir包含的目录存在,返回true
qDebug()<<dir.exists("C:/config.ini"); //如果C:/config.ini文件存在,返回true
qDebug()<<dir.exists("C:/System/"); //如果C:/System/目录存在返回true
|
3. 返回目录路径
QString dirName() const; //返回文件名称。如果DIR包含的是目录,不是一个文件名称,将返回空字符串。
QString filePath(const QString &fileName) const; //获取指定文件的当前路径。根据DIR路径属性决定返回值。
QString absoluteFilePath(const QString &fileName) const; //获取指定文件的绝对路径
QString relativeFilePath(const QString &fileName) const; //获取指定文件的相对路径
|
注意:以上函数都不会检测文件和路径是否真实存在。调用前需要使用exists函数确保路径正确。
示例:
QDir dir("./data.c");
qDebug()<<dir.dirName(); //输出 "data.c"
qDebug()<<dir.filePath("work.c");//输出 "./data.c/work.c"
qDebug()<<dir.absoluteFilePath("work.c");
//输出"D:/QtExample/dirfile/build-dirfile-Desktop_Qt_5_7_0_MinGW_32bit-Debug/data.c/work.c"
qDebug()<<dir.relativeFilePath("work.c"); //输出"work.c"
|
4. 判断路径的目录属性
booQDir::isAbsolute() const //如果目录为绝对路径,返回true,否则返回false
booQDir::isRelative() const //如果目录为相对路径,返回true,否则返回false
booQDir::isAbsolutePath(const QString &path)//目录为绝对路径返回true,目录为相对路径返回false。
booQDir::isReadable() const //判断目录或者文件是否可读,可读返回true
booQDir::isReadable() const //判断目录是否可读。Linux系统下某些目录普通用户无法读取。
|
5. 相对路径到绝对路径的转换
将相对路径转为绝对路径,如果路径已经是绝对路径,将不会产生作用。成功返回true。
示例:
QDir dir("./"); //构造目录
dir.makeAbsolute(); //转换路径
qDebug()<<dir.dirName(); //输出:"build-dirfile-Desktop_Qt_5_7_0_MinGW_32bit-Debug"
|
6. 返回应用程序当前的路径
[static] QString QDir::currentPath()
[static] QDir QDir::current()
|
示例:
QDir dir=QDir::current();
qDebug()<<dir.absolutePath(); //输出当前应用程序的绝对路径
qDebug()<<QDir::currentPath();//输出当前应用程序的绝对路径
|
7. 切换目录
boocd(const QString &dirName); //切换目录。
static boosetCurrent(const QString &path); //改变应用程序的工作路径
void QDir::setPath(const QString &path) //设置QDir包含的路径
|
8. 获取系统根目录路径
[static] QString QDir::rootPath()
[static] QDir QDir::root()
[static] QString QDir::homePath()
[static] QString tempPath();
|
rootPath 和root()返回系统的根路径。Windows系统下返回系统的根目录。比如:"C:/"。Linux下返回"/"。
homePath函数返回用户主目录绝对路径。例如: windos下返回"C:/Users/Administrator"
tempPath函数返回系统的临时目录绝对路径。例如:windos下返回"C:/Users/Administrator/AppData/Local/Temp"。
9. 删除目录和文件
booQDir::remove(const QString &fileName)
booQDir::removeRecursively()
boormpath(const QString &dirPath) const
boormdir(const QString &dirName) const;
|
Remove函数用于删除指定的文件,不能删除目录。成功删除返回true。
removeRecursively函数用于删除QDir包含的目录,并删除目录下的所有文件。成功删除返回true。
rmpath函数用于删除多层目录,但是需要确保目录路径下没有任何文件。成功删除返回true。
rmdir函数用于删除单层空目录,但是需要确保目录路径下没有任何文件。成功删除返回true。
10. 创建目录
boomkdir(const QString &dirName) const; //创建单层目录
boomkpath(const QString &dirPath) const; //创建多层目录
|
11. 目录或者文件重命名
boorename(const QString &oldName, const QString &newName);
|
rename用于给目录或者文件重命名,oldName旧名称,newName
示例:dir.rename("D:/work","D:/data");
12. 获取指定目录下所有的目录名称和文件名称
QStringList entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const;
QStringList entryList(const QStringList &nameFilters, Filters filters = NoFilter,SortFlags sort = NoSort) const;
|
Filters枚举值用于设置过滤目录的属性,SortFlags枚举值用于设置目录的排序方式。第二个函数多了一个QStringList参数,该参数用于设置过滤的文件后缀列表。目录读取成功将返回QStringList列表,失败返回空列表。
QDir::Dirs
| 列出匹配字符串名称过滤的目录
| QDir::AllDirs
| 列出所有目录,不管名称过滤
| QDir::Files
| 列出文件
| QDir::Drives
| 列出磁盘分区盘符(Unix Linux 忽略这个值)
| QDir::NoSymLinks
| 不列举符号链接
| QDir::AllEntries
| 列出目录、文件、磁盘分区盘符、符号链接
| QDir::NoDotAndDotDot
| 不列举 "." 和 ".."
| QDir::NoFilter
| 条目类型不做任何过滤,默认是这个
| QDir::Readable
| 列出本应用程序可以读取的文件。Readable 枚举值需要与 Dirs 或 Files 结合使用。
| QDir::Writable
| 列出本应用程序可以写入的文件。Writable 枚举值需要与 Dirs 或 Files 结合使用。
| QDir::Executable
| 列出本应用程序具有执行权限的文件。Executable 枚举值需要与Dirs或Files 结合使用。
| QDir::Modified
| 只列出曾经被修改过的文件(Unix系统忽略这个值)
| QDir::Hidden
| 列出隐藏文件(Unix系统以 '.' 开头的文件名)。
| QDir::System
| 列出系统文件(Unix系统中包含套接字、设备文件等。Windows系统中包含.lnk 文件)
| QDir::CaseSensitive
| 名称过滤字符串中字母是大小写敏感的。
|
QDir::Name
| 按名称排序
| QDir::Time
| 按时间排序(修改时间)
| QDir::Size
| 按大小排序
| QDir::Type
| 按类型排序(扩展名)
| QDir::Unsorted
| 不排序
| QDir::NoSort
| 不排序,默认是这个值
| QDir::DirsFirst
| 文件夹排在前面,文件排在后面
| QDir::DirsLast
| 文件夹排在后面,文件排在前面
| QDir::Reversed
| 逆序排列
| QDir::IgnoreCase
| 排序时大小写不敏感
| QDir::LocaleAware
| 根据当前本地化的设置进行恰当地排序
|
QDir dir("D:/"); //构造目录
QStringList infolist = dir.entryList(QDir::Files,QDir::Size);
for(int i=0; i<infolist.count(); i++)
qDebug() << infolist.at(i); //打印出列表中包含的信息
|
QDir dir("D:/"); //构造目录
QStringList list;
list<<"*.c"<<"*.h"<<"Q*"; //过滤以.c、.h结尾,以Q开头的文件和目录
QStringList infolist = dir.entryList(list,QDir::Files|QDir::Dirs,QDir::Size);
for(int i=0; i<infolist.count(); i++)
qDebug() << infolist.at(i); //打印出列表中包含的信息
|
13. 获取目录和文件的详细信息
QFileInfoList entryInfoList(const QStringList &nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort)
QFileInfoList entryInfoList(Filters filters = NoFilter, SortFlags sort = NoSort) const
|
entryInfoList形参与entryList函数形参一样,可以参考entryList函数的用法。entryList函数的返回值是QFileInfoList类型,每一个文件的信息由一个QFileInfo类型保存。比如:文件大小,访问权限,是否是目录等信息。QFileInfo详细参数在下一节进行介绍。
6.2 QFileInfo获取文件详细信息 QFileInfo类提供了获取系统文件信息的方法。可以获取文件的名称、在文件系统中的路径,文件的权限,文件的大小和最后修改/读取时间等信息。还可以区分目录、区分符号链接(快捷方式)。也可以获取Qt程序的内部资源系统文件信息。QFileInfo 既支持相对路径,也支持绝对路径访问一个文件,路径的用法与QDir类一样。
6.2.1 获取指定目录下的所有文件大小信息 #include <QApplication>
#include <QDir>
#include <QDebug>
int main(int argc, char *argv[])
{
QDir dir("C:/Users/Administrator/Desktop");
QFileInfoList infolist = dir.entryInfoList(QDir::Files);
for(int i=0; i<infolist.count(); i++)
{
QFileInfo info=infolist.at(i); //取出单个文件
if(info.isSymLink()) //判断是否是链接文件
{
qDebug()<<info.symLinkTarget(); //输出链接文件指向的真实地址
}
qDebug()<<info.absoluteFilePath(); //返回当前文件的绝对路径"
qDebug()<<info.size(); //返回当前的文件大小
}
return 0;
}
|
以上代码使用QDir的entryInfoList函数获取指定目录下的所有文件信息列表,然后通过QFileInfo的成员函数获取每个文件的大小信息,并区分是否是链接文件(快捷方式)。
6.2.2 函数介绍 1. 构造目录
QFileInfo(const QString &file)
QFileInfo(const QFile &file)
QFileInfo(const QDir &dir, const QString &file)
QFileInfo(const QFileInfo &fileinfo)
|
QFileInfo支持直接传递文件路径,也支持传递QDir和QFile包含的文件路径。
2. 设置QFileInfo访问的文件
QFileInfo构造函数没有指定文件路径,可以使用以下函数指定文件路径。每次修改了文件之后,需要调用refresh()函数刷新文件缓冲区,让QFileInfo重新读取文件。
void setFile(const QString &file);
void setFile(const QFile &file);
void setFile(const QDir &dir, const QString &file);
void refresh(); //刷新文件缓冲区
|
3. 判断文件是否真实存在
booexists() const; //判断QFileInfo当前包含的文件是否存在。返回true表示文件存在。
static booexists(const QString &file);
|
第二个exists函数属于静态函数,支持传入文件名,判断指定文件是否存在。返回true表示文件存在。
4. 获取文件的路径与后缀信息
QString filePath() const; //返回当前文件的路径包含文件名。(可能是绝对的也可能是相对的)。
QString absoluteFilePath() const; //返回当前文件的绝对路径包含文件名。
QString canonicalFilePath() const; //返回标准文件路径,不包含链接文件。如果文件不存在将返回空字符串。
QString fileName() const; //返回文件名称,不包含路径
QString baseName() const; //返回基本文件名称,去掉了文件的后缀。例如:data.tar.gz --->data
QString completeBaseName() const; //去掉文件最后一个.后缀。例如:data.tar.gz --->data.tar
QString suffix() const; //返回文件的后缀。例如:data.tar.gz --->gz
QString completeSuffix() const; //返回文件完整的后缀。例如:data.tar.gz --->tar.gz
|
注意:以上除了canonicalFilePath()函数会检查文件路径之外,其他函数都不会检测文件是否真实存在。
示例:
QFileInfo info("D:/data.zip.tar.gz"); //构造文件路径
qDebug()<<info.filePath(); //输出:"D:/data.zip.tar.gz"
qDebug()<<info.absoluteFilePath(); //输出:"D:/data.zip.tar.gz"
qDebug()<<info.canonicalFilePath(); //输出:"D:/data.zip.tar.gz"
qDebug()<<info.fileName(); //输出:"data.zip.tar.gz"
qDebug()<<info.baseName(); //输出:"data"
qDebug()<<info.completeBaseName(); //输出:"data.zip.tar"
qDebug()<<info.suffix(); //输出:"gz"
qDebug()<<info.completeSuffix(); //输出:"zip.tar.gz
|
5. 获取目录路径信息
QString path() const; //返回文件所在的路径。如果当前包含的是相对路径,返回的就是相对路径。
QString absolutePath() const; //返回当前文件的绝对路径。
QString canonicalPath() const; //返回标准路径。如果文件不存在,返回空字符串。
QDir dir() const; //返回文件当前路径的QDir对象。
QDir absoluteDir() const; //返回文件绝对路径的QDir对象。
|
注意:文件名后面不能加"/",否则会识别为路径
例如:QFileInfo info("./data.zip.tar.gz/"); 这样将会识别为./data.zip.tar.gz/路径。
6. 判断文件读写属性
booisReadable() const; //判断文件是否可读,文件可读返回true。
booisWritable() const; //判断文件是否可写,文件可写返回true。
booisExecutable() const; //判断文件是否可执行,文件执行返回true。
booisHidden() const; //文件是隐藏文件返回true。
|
7. 判断路径类型
booisRelative() const; //当前是相对路径返回true
booisAbsolute() const //当前是绝对路径返回true
boomakeAbsolute(); //将相对路径转为绝对路径
|
8. 判断文件的类型
booisFile() const; //判断是否是文件
booisDir() const; //判断是否是目录
booisSymLink() const;//判断是否是链接文件
booisRoot() const; //判断目录是否是根目录
QString symLinkTarget()//如果文件是链接文件,将返回链接文件指向的真实路径
|
9. 获取文件的分组情况
QString owner() const; //返回文件的所有者,没有将返回NULL
uint ownerId() const; //返回文件的所有者id。
QString group() const; //返回文件的当前用户组
uint groupId() const; //返回文件的当前用户组ID
|
以上几个属性在windows系统上不存在。一般在Linux下使用。
10. 获取文件的大小和修改时间
qint64 size() const; //返回文件的字节大小
QDateTime created() const; //返回文件的创建日期和时间
QDateTime lastModified() const; //返回文件最后修改日期和时间。
QDateTime lastRead() const; //返回最后一次读取该文件的日期和时间(访问)。
|
时间由QDateTime类进行表示。QDateTime类提供日期和时间相关表示方法。
示例:
QFileInfo info("./data.zip.tar.gz");//取出单个文件
qDebug()<<"字节大小:"<<info.size();
QDateTime time_1=info.created(); //创建时间
qDebug()<<time_1.toString("yyyy-MM-dd hh:mm:ss");
QDateTime time_2=info.lastModified(); //修改时间
qDebug()<<time_2.toString("yyyy-MM-dd hh:mm:ss");
QDateTime time_3=info.lastRead(); //最后访问时间
qDebug()<<time_3.toString("yyyy-MM-dd hh:mm:ss");
|
输出结果:
字节大小: 33880
"2016-09-20 12:54:23"
"2016-09-20 14:51:01"
"2016-09-20 12:54:23"
|
6.3 QFile文件读写操作 Qt 常见的文件读写类有三个QFile、QTextStream 和 QDataStream。其中QFile是基本的文件读写类,读写函数功能比较简单,它主要是面向字节数据进行读写,QFile不仅适合于普通的文件系统,而且对 Qt 程序内嵌的资源文件也是通用的,区别只是内嵌资源文件全是只读的。QFile可以单独使用,一般情况下都是配合QTextStream和QDataStream类进行读写文本。QFile继承关系如下图,QFile从QIODevice类派生,QIODevice类输入输出设备的抽象类;进程间通信、串口、网络等IO设备都从该类继承,QIODevice类是非常重要的类。从QIODevice类中除了派生了QFile类操作文件,还派生了一个QSaveFile类。
QSaveFile类是为了安全的进行写操作而设计的。当要写入数据时,会先建立一个临时的文件保存要写入的数据。如果在写入过程中没有错误发生,则使用commit() 提交到最终要写入的文件中去。这种机制确保了一旦发生写入错误,不会破坏源文件数据,当向磁盘写入数据时经常使用此类。QSaveFile会在写入过程中自动的检查错误,可以像QFile类一样操作文件。

图6-3-1 QFile继承关系
6.3.1 读写文本示例 #include <QApplication>
#include <QDir>
#include <QDebug>
#include <QFile>
int main(int argc, char *argv[])
{
QFile file_1("D:/text_1.txt");
file_1.open(QIODevice::ReadOnly);
QByteArray byte=file_1.readAll(); //读取所有数据
file_1.close();
QFile file_2("D:/text_2.txt");
file_2.open(QIODevice::WriteOnly);
file_2.write(byte); //写入数据
file_2.close();
return 0;
}
|
6.3.2 函数介绍 1. Open打开函数
booQFile::open(FILE * fh, OpenMode mode, FileHandleFlags handleFlags = DontCloseHandle);
booQFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags = DontCloseHandle)
booQFile::open(OpenMode mode)
|
Open函数使用OpenMode包含的模式打开文件,成功返回true。前两个函数是重载的函数。通过现有的文件指针和文件描述符打开文件,可以原来的基础上附加打开的选项模式。
支持的打开的模式:
QIODevice::NotOpen
| 不开放任何操作
| QIODevice::ReadOnly
| 读模式
| QIODevice::WriteOnly
| 写模式
| QIODevice::ReadWrite
| 读写模式
| QIODevice::Append
| 设备是在附加模式下打开,这样所有的数据都是写入到文件的末尾。
| QIODevice::Truncate
| 覆盖模式,之前所有设备内容将覆盖丢失。
| QIODevice::Text
| 表示读取的是普通的文本文件。
| QIODevice::Unbuffered
| 非缓冲设备。
|
注意以 QIODevice::Text 模式打开文件时,读写的数据可能会发生改变,因为QFile会自动转换换行符,读取得到的缓冲区数据与原始文件可能不一样。一般是用来读写普通文本文件使用,读写二进制数据时不能加QIODevice::Text 模式。文件打开操作完毕后可调用close函数关闭文件。
常用的模式配置举例:
file.open(QIODevice::WriteOnly); //以只写模式打开,会清空文件之前的数据
file.open(QIODevice::WriteOnly | QIODevice::Truncate); //只写模式,会清空文件之前的数据
file.open(QIODevice::WriteOnly | QIODevice::Append); //只写模式和追加模式,不会清空文件之前的数据
file.open(QIODevice::ReadWrite); //读写模式,不会清空文件之前的数据,如果文件不存在可以创建文件。
|
2. 复制文件
boocopy(const QString &newName);
static boocopy(const QString &fileName, const QString &newName);
|
copy函数用于创建一个新文件,然后将当前文件所有数据复制到新文件中,如果新文件已经存在,copy将会复制失败,返回false。第二个copy函数是静态函数,可以直接传入源文件和新文件名称进行复制。
示例:
QFile file("D:/text.txt");
file.copy("D:/text_1.txt"); //指定新文件名称
file.close(); //关闭文件
//调用静态函数实现文件复制
QFile::copy("D:/text.c","D:/text_1.c");
|
3. 创建链接文件
boolink(const QString &newName);
static boolink(const QString &oldname, const QString &newName);
|
链接文件的类型依赖于底层操作系统。windows下是快捷方式,Linux下是link链接文件。链接文件创建成功返回true。注意:windows系统下创建的链接文件必须以lnk为后缀。
示例:
QFile file("D:/text.txt");
file.link("D:/text.lnk"); //指定链接文件名称
file.close(); //关闭文件
//调用静态函数给指定文件创建快捷方式
QFile::link("D:/text.c","D:/text_1.lnk");
|
4. 文件重命名
boorename(const QString &newName);
static boorename(const QString &oldName, const QString &newName);
|
rename用于给文件重命名,成功返回true。第二个静态函数可以直接给指定的文件重命名。
5. 删除指定的文件
booremove();
static booremove(const QString &fileName);
|
静态函数支持传入删除的文件名,普通成员函数删除QFile包含的文件。
6. 判断文件是否存在
booexists() const;
static booexists(const QString &fileName);
|
7. 设置QFile包含的文件名称
QString fileName() const;
void setFileName(const QString &name);
|
8. 设置与获取文件的权限
Permissions permissions() const ; //获取打开文件的权限
static Permissions permissions(const QString &filename); //静态函数,获取指定文件的权限
boosetPermissions(Permissions permissionSpec) ; //设置打开的文件权限
static boosetPermissions(const QString &filename, Permissions permissionSpec);
|
Permissions权限枚举值:
QFileDevice::ReadOwner
| 文件所有者可读
| QFileDevice::WriteOwner
| 文件所有者可写
| QFileDevice::ExeOwner
| 文件所有者可执行
| QFileDevice::ReadUser
| 当前用户可读
| QFileDevice::WriteUser
| 当前用户可写
| QFileDevice::ExeUser
| 当前用户可执行
| QFileDevice::ReadGroup
| 用户组可读
| QFileDevice::WriteGroup
| 用户组可写
| QFileDevice::ExeGroup
| 用户组可执行
| QFileDevice::ReadOther
| 其他用户可读
| QFileDevice::WriteOther
| 其他用户可写
| QFileDevice::ExeOther
| 其他用户可执行
|
9. 获取与修改文件大小
qint64 size() const;
booresize(qint64 sz);
static booresize(const QString &filename, qint64 sz);
|
size()函数用于获取已经打开的文件大小,如果文件已经关闭,则无法确定实际大小。
resize()函数用于修改文件的大小,传入的参数单位是字节单位。只能将文件大小在源文件基础之上调小,多余的数据直接截断。
10. 向文件写数据
qint64 write(const char *data, qint64 len);
qint64 write(const char *data);
inline qint64 write(const QByteArray &data)
|
write函数继承于QIODevice类。write支持C语言风格的字符串传入,也支持QByteArray字节数组类类型传入。返回值是写成功的字节数量。
11. 从文件中读数据
qint64 read(char *data, qint64 maxlen);
QByteArray read(qint64 maxlen);
QByteArray readAll();
qint64 readLine(char *data, qint64 maxlen);
QByteArray readLine(qint64 maxlen = 0);
|
read函数继承于QIODevice类。read函数支持读取指定字节数量数据、支持一次性读取全部数据、支持读取一行数据。
12. 判断文件是否可读写
booisOpen() const;
booisReadable() const;
booisWritable() const;
|
13. 改变文件指针位置
qint64 pos() const; //获取文件指针位置
booseek(qint64 pos); //偏移文件指针位置
booatEnd() const; //判断文件是否到结尾
|
14. 刷新缓冲区
将缓冲区的数据全部写回文件。
15. 获取文件描述符
文件描述符是一个小整数,适用于标准C函数中的open或者ioctl函数使用。
16. 映射文件到内存空间
uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions);
boounmap(uchar *address);
|
实现的效果与Linux下的mmap函数一样。将指定文件映射到DDR内存空间进行操作。
6.3.3 读取BMP图片信息 本小节使用QFile类编写一个示例,读取BMP格式图片的信息。BMP是一种与硬件设备无关的图像文件格式,使用非常广。BMP是Windows环境中交换与图有关的数据的一种标准,在Windows环境中运行的图形图像软件都支持BMP图像格式。典型的BMP图像文件由以下四部分组成:

图6-3-2 BMP格式组成
文件头:它包含BMP图像文件的类型、内容尺寸和起始偏移量等信息。
字节顺序
| 数据类型
| 描述
| 1,2
| short
| 高8位为字母’B’,低8位为字母’M’
| 3,4,5,6
| int
| 文件大小
| 7,8
| short
| 保留字
| 9,10
| short
| 保留字
| 11,12,13,14
| int
| 位图数据偏移量
|
位图数据偏移量:是位图数据部分相对于文件首的起始偏移量。数据部分偏移量的存在,说明图像数据部分并不一定要紧随图像参数或调色板之后放置,BMP图片的制作者其实可以在调色板之后、数据部分之前填充任何内容,只要正确地设置偏移量即可。
根据以上的信息可以定义一个结构体来表示文件头信息:
typedef struct
{
short bfType; //表明位图文件的类型,必须为BM
long bfSize; //表明位图文件的大小,以字节为单位
short bfReserved1; //属于保留字,必须为本0
short bfReserved2; //也是保留字,必须为本0
long bfOffBits; //位图阵列的起始位置,以字节为单位
} T_BITMAPFILEHEADER;
|
文件参数:它包含图像的宽、高、压缩方法,以及颜色定义等信息。
字节顺序
| 数据类型
| 描述
| 15,16,17,18
| int
| 当前结构体的大小
| 19,20,21,22
| int
| 图像宽度(像素)
| 23,24,25,26
| int
| 图像高度(像素)
| 27,28
| short
| 固定为1
| 29,30
| short
| 每像素占用的位数,即bpp每个像素所需的位数。
| 31,32,33,34
| int
| 压缩方式
| 35,36,37,38
| int
| 像素点数据总共占用的字节数
| 39,40,41,42
| int
| 水平分辨率
| 43,44,45,46
| int
| 垂直分辨率
| 47,48,49,50
| int
| 引用色彩数
| 51,52,53,54
| int
| 关键色彩数
|
根据以上信息可以定义一个结构体表示文件参数信息:
typedef struct {
long biSize; //指出本数据结构所需要的字节数
long biWidth; //以象素为单位,给出BMP图象的宽度
long biHeight; //以象素为单位,给出BMP图象的高度
short biPlanes; //输出设备的位平面数,必须置为1
short biBitCount; //给出每个象素的位数
long biCompress; //给出位图的压缩类型
long biSizeImage; //给出图象字节数的多少
long biXPelsPerMeter; //图像的水平分辨率
long biYPelsPerMeter; //图象的垂直分辨率
long biClrUsed; //调色板中图象实际使用的颜色素数
long biClrImportant; //给出重要颜色的索引值
} T_BITMAPINFOHEADER;
|
下面新建新项目,基类选择 QWidget。实现查看指定BMP图片的属性信息。(配套程序编号CH6-1)
1. widget.ui界面内容

图6-3-3 界面布局
使用一个标签控件显示图片,单行编辑器显示文件的路径,两个按压按钮用于浏览图片路径和查看图片信息。图片信息使用消息对话框弹出显示。
2. widget.h文件代码
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QFile>
#include <QFileDialog>
#include <QPixmap>
#include <QMessageBox>
/*BMP图片信息结构体定义*/
#pragma pack(1) //以下结构体以一个字节对齐
typedef struct
{
short bfType; //表明位图文件的类型,必须为BM
long bfSize; //表明位图文件的大小,以字节为单位
short bfReserved1; //属于保留字,必须为本0
short bfReserved2; //也是保留字,必须为本0
long bfOffBits; //位图阵列的起始位置,以字节为单位
}T_BITMAPFILEHEADER;
typedef struct {
long biSize; //指出本数据结构所需要的字节数
long biWidth; //以象素为单位,给出BMP图象的宽度
long biHeight; //以象素为单位,给出BMP图象的高度
short biPlanes; //输出设备的位平面数,必须置为1
short biBitCount; //给出每个象素的位数
long biCompress; //给出位图的压缩类型
long biSizeImage; //给出图象字节数的多少
long biXPelsPerMeter; //图像的水平分辨率
long biYPelsPerMeter; //图象的垂直分辨率
long biClrUsed; //调色板中图象实际使用的颜色素数
long biClrImportant; //给出重要颜色的索引值
} T_BITMAPINFOHEADER;
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
QString fileName;
private slots:
void on_pushButton_open_clicked();
void on_pushButton_info_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
|
在widget.h文件中定义了两个存放BMP图片信息的结构体,在定义结构体时加上了#pragma pack(1)宏,让结构体成员按字节对齐。
3. widget.cpp代码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
//打开图片
void Widget::on_pushButton_open_clicked()
{
/*获取打开的文件名称*/
fileName = QFileDialog::getOpenFileName(this,
tr("打开BMP图片"), "D:/", tr("Image Files (*.bmp)"));
ui->label_show->setPixmap(QPixmap(fileName)); //显示图片
ui->label_show->setScaledContents(true);
ui->lineEdit->setText(fileName); //显示打开的路径
}
//查看图片信息
void Widget::on_pushButton_info_clicked()
{
if(ui->lineEdit->text().isEmpty())
{
QMessageBox::critical(this, tr("图片信息查询"),
tr("没有打开BMP图片,请检查路径信息!\n"),
QMessageBox::Ok);
return;
}
T_BITMAPFILEHEADER file_header;
T_BITMAPINFOHEADER file_info;
QString str_info; //保存解析读出的信息
QFile bmp_file(ui->lineEdit->text()); //指定图片路径
bmp_file.open(QIODevice::ReadOnly);
bmp_file.read((char*)&file_header,sizeof(T_BITMAPFILEHEADER));
bmp_file.read((char*)&file_info,sizeof(T_BITMAPINFOHEADER));
str_info+="图片名称: ";
str_info+=bmp_file.fileName();
str_info+="\n";
str_info+="文件大小: ";
str_info+=QString::number(file_header.bfSize/1024);
str_info+="kb\n";
str_info+="图片宽度: ";
str_info+=QString::number(file_info.biWidth);
str_info+="\n";
str_info+="图片高度: ";
str_info+=QString::number(file_info.biHeight);
str_info+="\n";
str_info+="图片位数: ";
str_info+=QString::number(file_info.biBitCount);
str_info+="\n";
QMessageBox::information(this, tr("图片信息查询"),str_info, QMessageBox::Ok);
}
|
widget.cpp代码中主要编写了两个按钮槽函数,用于浏览图片和显示图片属性信息。
4. 效果图
 图6-3-4 程序运行界面
6.4 QTextStream处理文件数据流 Qt提供的QTextStream文本流,实现了标准C++输入输出流的功能(iostream、fstream、sstream)并且支持各种文本字符编码。QTextStream 一般用于操作各种编码格式的文本文件(QFile 对象)或字符串(QString、QByteArray),也可以打开 stdin、stdout 和 stderr 命令行的输入输出,并且能够自动处理本地化编码和 Unicode 编码。QTextStream的构造函数不支持直接传递文件名,而是接收 QFile 基类 QIODevice的指针,可以用QFile对象的指针构造QTextStream ,在构造 QTextStream 之前要调用 QFile对象的open()函数按需要的模式打开文件,并检查是否正确打开。QTextStream常用的构造函数为:QTextStream(QIODevice *device);
6.4.1 QTextStream写文本流示例 #include <QApplication>
#include <QDebug>
#include <QFile>
#include <QTextStream>
int main(int argc, char *argv[])
{
QFile file("D:/text.txt");
if(!file.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text))
{
qDebug()<<"文件打开失败";
return 0;
}
QTextStream out(&file);
//向文件中写入数据
out << "Result: " << qSetFieldWidth(10) << left << 3.14 << 2.7;
file.close();
return 0;
}
|
结果:
 图6-4-1 写入文本结果
6.4.2 函数介绍 1. 构造QTextStream设备
QTextStream(QIODevice *device);
QTextStream(FILE *fileHandle, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
QTextStream(QString *string, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
QTextStream(QByteArray *array, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
QTextStream(const QByteArray &array, QIODevice::OpenMode openMode = QIODevice::ReadOnly);
|
QTextStream的构造函数支持传入QString、QByteArray、FILE类型。也就是说,QTextStream除了操作文件设备,也可以操作QString、QByteArray等存在缓冲区的类型。注意最后一个构造函数的形参,QByteArray前加了consts表明传入的QByteArray只读。
示例:
QString s;
QTextStream out(&s);
out<<QObject::tr("整数=")<<1234<<qSetFieldWidth(10);
out<<"Qt";
qDebug()<<s;
|
输入结果:"整数=1234 Qt"
2. 流操作符介绍
操作符
| 作用描述符
| bin
| 读写二进制整数,等同于 setIntegerBase(2)
| oct
| 读写八进制整数,等同于 setIntegerBase(8)
| dec
| 读写十进制整数,等同于 setIntegerBase(10)
| hex
| 读写十六进制整数,等同于 setIntegerBase(16)
| showbase
| 强制显示数值进制前缀,比如 "0x" 、"0"、"0b"
等同于setNumberFlags(numberFlags() | ShowBase)
| forcesign
| 强制显示正负号。等同于 setNumberFlags(numberFlags() | ForceSign)
| forcepoint
| 强制显示小数点。等同于setNumberFlags(numberFlags() | ForcePoint)
| noshowbase
| 不显示进制的前缀。等同于 setNumberFlags(numberFlags() & ~ShowBase)
| noforcesign
| 不显示正负号。等同于 setNumberFlags(numberFlags() & ~ForceSign)
| noforcepoint
| 不显示小数点。等同于 setNumberFlags(numberFlags() & ~ForcePoint)
| uppercasebase
| 显示大写的进制前缀。如 "0X" 、"0B"。
等同于setNumberFlags(numberFlags() | UppercaseBase)
| uppercasedigits
| 基数大于10进制的数值使用大写字母表示。比如16进制 "FF11"。
等同于setNumberFlags(numberFlags() | UppercaseDigits)
| lowercasebase
| 显示小写的进制前缀,如 "0x" 、"0b"
等同于 setNumberFlags(numberFlags() & ~UppercaseBase)
| lowercasedigits
| 基数大于10进制的数值使用小写字母表示。比如16进制 "ff11"。
等同于 setNumberFlags(numberFlags() & ~UppercaseDigits).
| fixed
| 固定小数点显示实数(比如 float、double 类型)。比如 1234.1234。
等同于 setRealNumberNotation(FixedNotation).
| scientific
| 以科学计数法显示实数,比如 1.0241234e3。
等同于 setRealNumberNotation(ScientificNotation)
| left
| 变量显示时左对齐。等同于 setFieldAlignment(AlignLeft)
| right
| 变量显示时右对齐。等同于 setFieldAlignment(AlignRight)
| Center
| 变量显示时居中对齐。等同于 setFieldAlignment(AlignCenter)
| end
| 添加换行符并清空输出缓存。等同于 stream << '\n' << flush;
| flush
| 清空输出缓冲区,把缓冲数据都写到输出文本流。等同于 QTextStream::flush()
| reset
| 重置全部格式。等同于 QTextStream::reset()
| ws
| 跳过输入文本流里的空白字符(包括空格、制表符、换行符等),直至遇到非空白字符。等同于 QTextStream::skipWhiteSpace()
| bom
| 写入 Unicode 文本时需要设置。等同于 setGenerateByteOrderMark(true)
|
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDataStream>
#include <QTextStream>
#include <QObject>
int main(int argc, char *argv[])
{
QFile file("D:/text.txt");
if(!file.open(QIODevice::ReadWrite|QIODevice::Text))
{
qDebug()<<"文件打开失败";
return 0;
}
QTextStream out(&file);
out<<QObject::tr("写二进制整数:")<<bin<<1234<<endl;
out<<QObject::tr("写八进制整数:")<<oct<<1234<<endl;
out<<QObject::tr("写十进制整数:")<<dec<<1234<<endl;
out<<QObject::tr("写十六进制整数:")<<hex<<1234<<endl;
out<<QObject::tr("固定小数点位数显示浮点数:")<<fixed<<1234.1234<<endl;
out<<endl;
/*显示前缀符号*/
out<<QObject::tr("-----显示前缀符号和正负符号-----")<<endl;
out<<QObject::tr("写二进制整数:")<<showbase<<forcesign<<bin<<1234<<endl;
out<<QObject::tr("写八进制整数:")<<oct<<1234<<endl;
out<<QObject::tr("写十进制整数:")<<dec<<1234<<endl;
out<<QObject::tr("写十六进制整数:")<<hex<<1234<<endl;
out<<QObject::tr("固定小数点位数显示浮点数:")<<fixed<<1234.1234<<endl;
file.close();
return 0;
}
|
数据写到文本文件中的效果如下:

图6-4-2 写入文本的结果
文件中的内容如下图所示:

QFile file("D:/text.txt");
if(file.open(QIODevice::ReadOnly|QIODevice::Text))
{
QTextStream out(&file);
int data;
QString text;
out>>text>>data;
file.close();
qDebug()<<text<<data;
//读出的结果:"写十进制整数" 1234
}
|
3. 设置读写的设备
除了在构造函数里指定读写的设备,还可以通过setDevice函数进行设置。
void QTextStream::setDevice(QIODevice *device) //设置QTextStream操作的设备
QIODevice *QTextStream::device() const //获取设置的设备
|
4. 设置字段宽度
void QTextStream::setFieldWidth(int width) //设置字段宽度
int QTextStream::fieldWidth() const //获取设置的字段宽度
|
5. 设置填充字符
void QTextStream::setPadChar(QChar ch)
QChar QTextStream::padChar() const
|
示例:
QString s;
QTextStream out(&s);
out.setFieldWidth(10);
out.setFieldAlignment(QTextStream::AlignCenter);
out.setPadChar('-');
out << "Qt" << "xl!";
qDebug()<<s;
|
输出结果:"----Qt-------xl!----"
6. 设置浮点数的精度
公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满)
我知道了
|