Qt文件读写

做一个简单的文件读写,我们把一个结构体内的数据写入到二进制文件中,并重新读取解析。代码结构如下:

项目名称随便起就好了。main.cpp是主函数;DataHandler实现文件的写与读,还要模拟过程;Definition.h放置自己常用的定义。

DataHandler

头文件的声明如下:

cpp 复制代码
#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文件并解析。具体实现如下:

cpp 复制代码
#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

cpp 复制代码
#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数据类型。

主函数

主函数定义如下:

cpp 复制代码
#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文件后,重新读取并解析,解析完成后退出。

相关推荐
benchmark_cc25 分钟前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu38 分钟前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
Wang's Blog43 分钟前
Java 项目实战: 交友项目 - 个人资料管理的更新接口实现与坑
java·开发语言·交友
CoderYanger1 小时前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
估值探索者1 小时前
【Python量化选股流水线 #04】选股器好不好用?「昨日候选→今日表现」回看验收
开发语言·python·股票数据·股票数据api接口
爱喝热水的呀哈喽2 小时前
HEJIAN RESEARCH
开发语言·matlab
白露与泡影2 小时前
后端 Java 面试核心八股汇总|高频面试题 + 解析,覆盖基础到进阶
java·开发语言·面试
xifangge20253 小时前
基于 JavaScript 实现 CNC 数控切削参数与螺纹公差纯前端核算引擎
开发语言·前端·javascript
“AI国潮设计-小江”3 小时前
【AIGC实战】Python+SDXL批量生成「潮汕英歌舞冰淇淋蛋糕&红桃粿咖啡」IP,固定角色形象批量出甜品商业效果图
开发语言·人工智能·python·prompt·aigc
\光辉岁月/3 小时前
3.包装类
java·开发语言·包装类