龙空技术网

从零开始学Qt(53):Qt预定义编码二进制文件的读写

未来奇兵 367

前言:

现在同学们对“python读二进制dat文件”可能比较讲究,各位老铁们都想要分析一些“python读二进制dat文件”的相关内容。那么小编同时在网上搜集了一些关于“python读二进制dat文件””的相关知识,希望大家能喜欢,兄弟们快快来学习一下吧!

二进制文件读写概述

除了文本文件之外,其他需要按照一定的格式定义读写的文件都称为二进制文件。每种格式 的二进制文件都有自己的格式定义,写入数据时按照一定的顺序写入,读出时也按照相应的顺序读出。

Qt使用QFile和QDataStream进行二进制数据文件的读写。QFile负责文件的IO设备接口, 即与文件的物理交互,QDataStream以数据流的方式读取文件内容或写入文件内容。

根据QDataStream保存文件时使用的数据编码的方式不同,可以保存为两种文件。

(1)用Qt预定义编码保存各种类型数据的文件,这里定义文件后缀为“.stm”。Qt预定义编码是指 在写入某个类型数据,如整形数、字符串等到文件流时,使用Qt预定义的编码。可以将这种Qt预定义数据格式编码类比于HTML的标记符,Qt写入某种类型数据时用了Qt预定义的标记符,读出数据时,根据标记符读出数据。使用Qt预定义编码保存的流文件,某些字节是QDataStream自己写入的,我们并不完全知道文件内每个字节的意义,但是用QDataStream可以读出相应的数据。

(2) 标准编码数据文件,定义文件后缀为“.dat”。在将数据写到文件时,完全使用数据的二进制原始内容,每个字节都有具体的定义,在读出数据时,只需根据每个字节的定义读出数据即可。

本文介绍第一种类型的二进制文件的读写方法。第二种在下一篇文章介绍。示例的界面如下图所示,用于编辑个人信息,提供保存和读取功能。

保存为stm文件

先看文件保存功能,因为从文件保存功能的代码可以看出文件内数据的存储顺序。在图中窗口上编辑个人信息数据后,单击工具栏上的“保存stm文件”,可以使用Qt预定义编码方式保存文件。此按钮的响应代码如下:

void MainWindow::on_actionSaveStm_triggered(){ //以Qt预定义编码保存文件  QString curPath=QDir::currentPath();  QString aFileName=QFileDialog::getSaveFileName(this, "选择保存文件",curPath, "Qt预定义编码数据文件(*.stm)");  if(aFileName.isEmpty())  	return;  if(saveDataAsStream(aFileName))  	QMessageBox::information (this,"提示消息","文件已经成功保存!");}
bool MainWindow::saveDataAsStream(QString &aFileName){ //将模型数据保存为Qt预定义编码的数据文件  QFile aFile(aFileName);  if(!(aFile.open(QIODevice::WriteOnly | QIODevice::Truncate)))  	return false;  QDataStream aStream(&aFile);  aStream.setVersion(QDataStream::QDataStream::Qt_5_14); //流版本号,写入和读取版本要兼容    QString name=ui->edtName->text();  aStream<<name; //写入文件流,字符串    int sex=ui->comboBoxSex->currentIndex();  aStream<<sex; // 写入文件流,整数    bool isMarriage=ui->checkBoxMarriage->isChecked();  aStream<<isMarriage; // 写入文件流,bool    int age=ui->spinBoxAge->value();  aStream<<age; // 写入文件流,整数    double height=ui->doubleSpinBoxHeight->value();  aStream<<height; //写入文件流,double    QDate birthDate=ui->dateEditBirthday->date();  aStream<<birthDate;//写入文件流,QDate    aFile.close();  return true;}

自定义函数saveDataAsStream()将个人信息数据保存为一个stm文件。代码首先是创建QFile对象aFile打开文件,然后创建QDataStream对象aStream与QFile对象关联。

在开始写数据流之前,为QDataStream对象aStream设置版本号,即调用setVersion()函数, 并传递一个QDataStream::Version枚举类型的值。

aStream.setVersion(QDataStream::QDataStream::Qt_5_14);

这表示aStream将以QDataStream::Qt_5_14版本的预定义类型写文件流。

注意以Qt的预定义类型编码保存的文件需要指定流版本号,因为每个版本的Qt对数据类型的编码可能有差别,需要保证写文件和读文件的流版本是兼容的。

接下来,就是按照需要保存数据的顺序写入文件流。向文件写入数据时,直接用流的输入操作,如:

aStream<<name; //写入文件流,字符串

数据流写入数据时都使用运算符“<<”,不论写的是int、double,还是字符串。除了可以写 入基本的数据类型外,QDataStream流操作还可以写入很多其他类型的数据,如QBrush、QColor、Qlmage、Qlcon等,这些称为可序列化的数据类型(Serializing Qt Data Types)。

QDataStream以流操作写入这些数据时,我们并不知道文件里每个字节是如何存储的,但是 知道数据写入的顺序,以及每次写入数据的类型。在文件数据读出时,只需按照顺序和类型对应读出即可。

stm文件格式

根据saveDataAsStream()函数的代码,可知Qt预定义编码保存的stm文件的格式,如下图

所示。

从图中可以知道stm文件的数据存储顺序和类型,但是并不知道int类型的数据存储为几个字节以及QString类型的数据是如何定义长度和字符内容的,其实也不需要知道这些具体的 存储方式,在从文件读出时,只需按照顺序和类型读出数据即可。

读取stm文件

下面是工具栏按钮“打开stm文件”的响应代码及相关函数代码,选择需要打开的stm文件 后,主要是调用自定义函数openDataAsStream()将其打开。

void MainWindow::on_actionOpenStm_triggered(){ //打开stm文件  QString curPath=QDir::currentPath();  QString aFileName=QFileDialog::getOpenFileName (this, "打开一个文件",curPath,"Qt预定义编码数据文件(*.stm)");  if(aFileName.isEmpty())  	return;  if(openDataAsStream(aFileName))  	QMessageBox::information(this, "提示消息","文件己经打开!");}
bool MainWindow::openDataAsStream(QString &aFileName){ //从stm文件读入数据QFile aFile(aFileName);if(!(aFile.open(QIODevice::ReadOnly)))	return false;QDataStream aStream(&aFile);aStream.setVersion(QDataStream::Qt_5_14); //设置流文件版本号  QString name;aStream>>name; //读取文件流,字符串ui->edtName->setText(name);  int sex;aStream>>sex; // 读取文件流,整数ui->comboBoxSex->setCurrentIndex(sex);  bool isMarriage;aStream>>isMarriage; // 读取文件流,boolui->checkBoxMarriage->setChecked(isMarriage);  int age;aStream>>age; // 读取文件流,整数ui->spinBoxAge->setValue(age);  double height;aStream>>height; //读取文件流,doubleui->doubleSpinBoxHeight->setValue(height);  QDate birthDate;aStream>>birthDate;//读取文件流,QDateui->dateEditBirthday->setDate(birthDate);  aFile.close();return true;}

读取stm文件的数据之前也必须设置QDataStream的流版本号,应该等于或高于数据保存时的流版本号。

然后就是按照写入数据时的顺序和类型,相应地读出每个数据。

总结

使用QDataStream的流操作方式读写文件的特点如下。

读写操作都比较方便,支持读写各种数据类型,包括Qt的一些类,还可以为流数据读写扩展自定义的数据类型。读写某种类型的数据时,只要是流支持即可,而在文件内部是如何存储的,用户无需关心,由Qt预定义。写文件和读文件时必须保证使用的流版本兼容,即流的版本号相同,或读取文件的流版本 号高于写文件时的流版本号。这是因为在不同的流版本中,流支持的数据类型的读写方式 可能有所改变,必须保证读写版本的兼容。用这种方式保存文件时,写入数据采用Qt预定义的编码,即写入文件的二进制编码是由 Qt预定义的,写多少个字节、字节是什么样的顺序,用户是不知道的。如果是由QDataStream 读取数据,只需按类型读出即可。但是,如果由这种方法创建的文件是用于交换的,需要用其他的编程语言(如Matlab)来读取文件内容,则存在问题了。因为其他语言并没有与 Qt的流写入完全一致的流读出功能,例如,其他语言并不知道Qt保存的QString或QFont 的内容是如何组织的。

标签: #python读二进制dat文件