实例功能概述
除了文本文件之外,其他需要按照一定的格式定义读写的文件都称为二进制文件。每种格式的二进制文件都有自己的格式定义,写入数据时按照一定的顺写入,读出时也按照相应的顺读出。例如地球物理中常用的SEG-Y格式文件,必须按照其标准格式要求写入数据才符合这种文件的格式规范,读取数据时也需要按照格式定义来读出。
Qt 使用 QFile 和 QDataStream 进行二进制数据文件的读取。QFile 负责文件的 IO 设备接口,即与文件的物理交互,QDataStream 以数据流的方式读取文件内容或写入文件内容。
我们依然是用一个例子来演示二进制文件读写,界面如下:
实例中以表格编辑一个数据表,采用 Model/View
结构,编辑后的数据保存为二进制文件。
根据 QDataStream 保存文件时使用的数据编码的方式不同,可以保存为两种文件。
- 用 Qt 预定义的编码保存各种类型的数据文件,定义文件后缀为“.stm”。Qt 预定义编码是指在写入某个类型数据,如整形数、字符串等到文件流时,使用 Qt 预定义的编码。可以将这种 Qt 预定义数据格式编码类比 HTML 的标记符,Qt 写入某种类型的数据时用了 Qt 预定义的标记符,独处数据时,根据标记符读出数据。使用 Qt 预定义编码保存流文件,某些字节是 QDataStream 自己写入的,我们并不完全知道文件内每个字节的意义,但使用 QDataStream 可以读出相应的数据。
- 标准编码数据文件,定义文件后缀为“.dat”。在将数据写到文件时,完全使用数据的二进制原始内容,每个字节都有具体定义,在读出数据时,只需根据每个字节的定义读出数据即可。
编写的例子具有以下功能:
- 可以在表格内编辑数据,同样的表格数据内容可以保存为两种格式的文件,Qt 预定义编码文件(stm 文件)和标准编码文件(dat 文件);
- 界面上的表格数据可以修改,可以添加行,插入列,删除行;
- 可以读取 stm 文件或 dat 文件,虽然文件格式不一样,但对相同的界面数据表存储的文件的实质内容是由于的。
实例的主窗口使用了 Model/View
结构、标准项数据模型(QStandardItemModel)和选择模型(QItemSelectionModel),界面上使用了 QTableView 组件,还有代理组件。这些设计 Model/View
的设计,以后得文章会讲。
为了便于理解后面的程序,这里给出 MainWindow 类中自定义的一些变量和函数,具体如下:
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
//用于状态栏的信息显示
QLabel *LabCellPos; //当前单元格行列号
QLabel *LabCellText; //当前单元格内容
QWIntSpinDelegate intSpinDelegate; //整型数
QWFloatSpinDelegate floatSpinDelegate; //浮点数
QWComboBoxDelegate comboBoxDelegate; //列表选择
QStandardItemModel *theModel;//数据模型
QItemSelectionModel *theSelection;//Item选择模型
void resetTable(int aRowCount); //表格复位,设定行数
bool saveDataAsStream(QString& aFileName);//将数据保存为数据流文件
bool openDataAsStream(QString& aFileName);//读取数据流文件
bool saveBinaryFile(QString& aFileName);//保存为二进制文件
bool openBinaryFile(QString& aFileName);//打开二进制文件
};
Qt 预定义编码文件的读写
保存为 stm 文件
首先看文件保存功能,因为从文件保存功能的代码可以看出文件内数据的存储顺序。在 UI 界面上点击“保存 stm”文件。可以使用 Qt 预定义编码方式保存文件。此按钮响应代码如下:
void MainWindow::on_actSave_triggered()
{
//以Qt预定义编码保存数据文件
QString curPath=QDir::currentPath();
QString aFileName=QFileDialog::getSaveFileName(this,tr("选择保存文件"),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::Qt_5_9); //设置版本号,写入和读取的版本号要兼容
qint16 rowCount=theModel->rowCount(); //数据模型行数
qint16 colCount=theModel->columnCount(); //数据模型列数
aStream<<rowCount; //写入文件流,行数
aStream<<colCount;//写入文件流,列数
//获取表头文字
for (int i=0;i<theModel->columnCount();i++)
{
QString str=theModel->horizontalHeaderItem(i)->text();//获取表头文字
aStream<<str; //字符串写入文件流,Qt预定义编码方式
}
//获取数据区的数据
for (int i=0;i<theModel->rowCount();i++)
{
QStandardItem* aItem=theModel->item(i,0); //测深
qint16 ceShen=aItem->data(Qt::DisplayRole).toInt();
aStream<<ceShen;// 写入文件流,qint16
aItem=theModel->item(i,1); //垂深
qreal chuiShen=aItem->data(Qt::DisplayRole).toFloat();
aStream<<chuiShen;//写入文件流, qreal
aItem=theModel->item(i,2); //方位
qreal fangWei=aItem->data(Qt::DisplayRole).toFloat();
aStream<<fangWei;//写入文件流, qreal
aItem=theModel->item(i,3); //位移
qreal weiYi=aItem->