找回密码
 立即注册
Qt开源社区 门户 查看内容

QT软件开发-第六章 文件与目录操作

2019-4-21 06:54| 发布者: admin| 查看: 4438| 评论: 0

摘要: 点击上方蓝字关注我们实际开发中,几乎所有的应用程序都要在文件系统中进行文件访问和读写操作,在学习复杂的应用程序之前,必须先扎实地学好文件操作相关的类。Qt中涉及文件操作的类比较多,本章节主要重点介绍最常 ...


点击上方蓝字关注我们





实际开发中,几乎所有的应用程序都要在文件系统中进行文件访问和读写操作,在学习复杂的应用程序之前,必须先扎实地学好文件操作相关的类。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. 相对路径到绝对路径的转换

booQDir::makeAbsolute()

将相对路径转为绝对路径,如果路径已经是绝对路径,将不会产生作用。成功返回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列表,失败返回空列表。

  • Filters枚举值

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

名称过滤字符串中字母是大小写敏感的。

  • SortFlags枚举值

QDir::Name

按名称排序

QDir::Time

按时间排序(修改时间)

QDir::Size

按大小排序

QDir::Type

按类型排序(扩展名)

QDir::Unsorted

不排序

QDir::NoSort

不排序,默认是这个值

QDir::DirsFirst

文件夹排在前面,文件排在后面

QDir::DirsLast

文件夹排在后面,文件排在前面

QDir::Reversed

逆序排列

QDir::IgnoreCase

排序时大小写不敏感

QDir::LocaleAware

根据当前本地化的设置进行恰当地排序

  • 示例1:列出指定目录下的所有文件

QDir dir("D:/"); //构造目录

QStringList infolist = dir.entryList(QDir::Files,QDir::Size);

for(int i=0; i<infolist.count(); i++)

qDebug() << infolist.at(i); //打印出列表中包含的信息

  • 示例2:过滤指定后缀的文件和目录

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. 刷新缓冲区

booQFileDevice::flush()

将缓冲区的数据全部写回文件。

    15. 获取文件描述符

int handle() const;

文件描述符是一个小整数,适用于标准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(已满) 我知道了