做一个简单的文件读写,我们把一个结构体内的数据写入到二进制文件中,并重新读取解析。代码结构如下:
项目名称随便起就好了。main.cpp是主函数;DataHandler实现文件的写与读,还要模拟过程;Definition.h放置自己常用的定义。
DataHandler
头文件的声明如下:
#ifndef DATAHANDLER_H
#define DATAHANDLER_H
#include <QFile>
#include <QDir>
#include <QFile>
#include <QObject>
#include <QDateTime>
#include <QThread>
#include <QDataStream>
#include <QtEndian>
#include <QCoreApplication>
#include "Definition.h"
class DataHandler: public QObject
{
Q_OBJECT
public:
explicit DataHandler(QObject *parent = nullptr);
void writeData(const DataFrame& headNode, const QByteArray& datagram);
void resetDataFrame();
void simulateFunc();
void analyse();
private:
QFile _File;
DataFrame _DataFrame;
int _id;
QDataStream _DataStream;
};
#endif // DATAHANDLER_H
其中,成员变量_File用来打开文件,_DataFrame是一个结构体,放置需要写的数据,_DataStream绑定文件后,可以通过DataStream写入数据。writeData()用来往文件中写数据,resetDataFrame()可以重置DataFrame,simulateFunc()进行模拟测试过程;analyse()读取已经保存的.dat文件并解析。具体实现如下:
#include "DataHandler.h"
DataHandler::DataHandler(QObject *parent): _id(0)
{
}
void DataHandler::writeData(const DataFrame& headNode, const QByteArray& datagram)
{
/*
QByteArray _head;
quint16 _id;
quint16 _info_length;
QString _info;
quint32 _datagram_length;
*/
_DataStream.writeRawData(headNode._head.data(), headNode._head.size());
_DataStream.writeRawData((char*)&headNode._id, sizeof(headNode._id));
_DataStream.writeRawData((char*)&headNode._info_length, sizeof(headNode._info_length));
QByteArray info = QByteArray::fromRawData((char*)headNode._info.toUtf8().data(), headNode._info.toUtf8().size());
_DataStream.writeRawData(info.data(), info.size());
_DataStream.writeRawData((char*)&headNode._datagram_length, sizeof(headNode._datagram_length));
_DataStream.writeRawData((char*)&datagram, datagram.size());
}
void DataHandler::resetDataFrame()
{
/*
QByteArray _head;
quint16 _id;
quint16 _info_length;
QString _info;
quint32 _datagram_length;
*/
_DataFrame._head.resize(DATAFRAME_HEAD_SIZE);
_DataFrame._head[0] = 0x16;
_DataFrame._head[1] = 0x06;
_DataFrame._head[2] = 0x00;
_DataFrame._head[3] = 0x16;
_DataFrame._id = this->_id++;
_DataFrame._info = QString::fromLocal8Bit("Test Data...");
_DataFrame._info_length = _DataFrame._info.size();
_DataFrame._datagram_length = 0;
}
void DataHandler::simulateFunc()
{
/* 模拟测试过程 */
QString filepath = "./SimulateFunc.dat";
_File.setFileName(filepath);
bool success = _File.open(QIODevice::WriteOnly);
if(!success) return;
_DataStream.setDevice(&_File);
_DataStream.setByteOrder(QDataStream::LittleEndian);
int count = 5;
while(count--) {
QByteArray datagram;
datagram.resize(10);
this->resetDataFrame();
_DataFrame._datagram_length = datagram.size();
writeData(_DataFrame, datagram);
qDebug() << "write datagram...";
QThread::sleep(1);
}
_File.close();
}
void DataHandler::analyse()
{
QString filepath = "./SimulateFunc.dat";
QFile file(filepath);
if(!file.open(QIODevice::ReadOnly)) return ;
QByteArray datagram = file.readAll();
file.close();
if(datagram.isEmpty()) return;
/*
QByteArray _head;
quint16 _id;
quint16 _info_length;
QString _info;
quint32 _datagram_length;
*/
int file_seek = 0; // 位置指针
while(file_seek < datagram.size()) {
int pos = datagram.mid(file_seek, DATAFRAME_HEAD_SIZE).indexOf(_DataFrame._head);
if(pos == -1) {
qDebug() << "Can't Find Head!";
return;
}
file_seek += DATAFRAME_HEAD_SIZE;
quint16 id = qFromLittleEndian<quint16>((char*)datagram.mid(file_seek, sizeof(_DataFrame._id)).data());
file_seek += sizeof (_DataFrame._id);
qDebug() << "ID: " << id;
quint16 info_length = qFromLittleEndian<quint16>((char*)datagram.mid(file_seek, sizeof(_DataFrame._info_length)).data());
file_seek += sizeof (_DataFrame._info_length);
qDebug() << "Info Length: " << id;
QString info = QString::fromLocal8Bit((char*)datagram.mid(file_seek, info_length).data(), info_length);
file_seek += info_length;
qDebug() << "Info: " << info;
quint32 datagram_length = qFromLittleEndian<quint32>((char*)datagram.mid(file_seek, sizeof(_DataFrame._datagram_length)).data());
file_seek += sizeof (_DataFrame._datagram_length);
qDebug() << "Datagram Length: " << datagram_length;
QByteArray datagram_core = datagram.mid(file_seek, datagram_length);
file_seek += datagram_length;
}
}
实现过程中有几个点需要注意:1. 因为平台可能有点不一样,我全部设置成小端序的文件读写;2. 尽量全部保持同样的写文件接口,比如使用了writeRawData(),就全部都有这个写; 3. 注意文件指针file_seek位置的移动,不然数据会解析失败。
Definition.h
#ifndef DEFINITION_H
#define DEFINITION_H
#include <QDebug>
#include <QObject>
#include <QtEndian>
#include <QDataStream>
#define DATAFRAME_HEAD_SIZE 4
typedef struct DataFrame
{
QByteArray _head;
quint16 _id;
quint16 _info_length;
QString _info;
quint32 _datagram_length;
};
#endif // DEFINITION_H
这里包含了一些常见的Qt数据类型。
主函数
主函数定义如下:
#include <QCoreApplication>
#include "DataHandler.h"
#include <QDebug>
int main(int argc, char *argv[])
{
DataHandler handler;
handler.simulateFunc();
handler.analyse();
qDebug() << "Finished!";
return 0;
}
模拟的结果如下:
我们假设放入5个节点数据,存入.dat文件后,重新读取并解析,解析完成后退出。