[Qt5] QJson库进行存储、加载数据

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: [Qt5] QJson库进行存储、加载数据

一. Boost库介绍

利用Boost库对视觉任务参数的存读时,有一个缺陷就是如果UI界面新增参数时,在界面初始化的时候会读取不到这个新增的参数,导致原任务设置好的的参数会被清掉进而变成默认参数,需要重新做任务保存参数。这对项目初期开发阶段而言非常不友好,增大调试时间成本。

一般需要增加版本号来解决上述的问题:

namespace boost
{
  namespace serialization
  {
    template<typename Archive>
    void serialize(Archive & ar, MS_CreateModelSingle_Params & d, const unsigned int version)
    {
      //VISION_LOG_INFO("%d", version);查看版本号
      ar & BOOST_SERIALIZATION_NVP(d.m_isPreventReverse);//是否启用防反
      ar & BOOST_SERIALIZATION_NVP(d.m_threshLow);       //阈值下限
      ar & BOOST_SERIALIZATION_NVP(d.m_threshHigh);      //阈值上限
      ar & BOOST_SERIALIZATION_NVP(d.m_area);            //面积
      if(version == 2) //只有 version = 新版本号才读取新参数
      {
        ar & BOOST_SERIALIZATION_NVP(d.m_areaRatio);       //面积占比
      }
    }
  }
}
BOOST_CLASS_VERSION(MS_CreateModelSingle_Params, 2);//当前新版本号,重新保存任务版本号将会更新

这样的话,在初始化的时候就不会读取到新增的参数,也就不会崩溃了。只有在重新保存参数的时候,才会将新增的参数保存到任务文件中。


二. QJson库介绍

本文使用QJson库来作为参数的保存与读取,不使用版本信息也可解决上述Boost库存在的缺陷。

JSON(JavaScript对象表示法)是一种轻量级的数据交换格式。它可以表示整数,实数,字符串,值的有序序列以及名称/值对的集合。


关于Qt中对JSON的生成与解析,Qt5以前的版本,可以使用QJson库,需要单独下载、编译,才能使用。到了 Qt5,提供了专门的QJsonDocument及其相关类来读和写JSON文档。

Json类 介绍
QJsonDoucument 它封装了一个完整的 JSON 文档,并且可以从 UTF-8 编码的基于文本的表示以及 Qt 自己的二进制格式读取和写入该文档
QJsonArray JSON 数组是一个值列表。可以通过从数组中插入和删除 QJsonValue 来操作该列表
QJsonObject JSON 对象是键值对的列表,其中键是唯一的字符串,值由 QJsonValue 表示
QJsonValue 该类封装了 JSON 支持的数据类型

三. QJson库生成与解析结构体数据

安装环境:本文使用的Qt版本—Qt5.12.10

1、包含头文件:

#include <QJsonDocument>

2、将结构体中的数据序列化成本地Json数据(toJson — 生成数据),

struct MS_EdgeLineFitParam
{
    //初始化结构体内数据
  MS_EdgeLineFitParam()
  {
    m_isAssignCenterEdge = false;
    m_measureWidth = 5;
    m_measureHeight = 0.0;
  }
  bool   m_isAssignCenterEdge;     
  int    m_measureWidth;           
  double m_measureHeight;   
  //将结构体中的数据序列化成本地`Json`数据
  QJsonValue toJson()
  {
      // 定义 { } 对象  
    QJsonObject jObj; 
    // 插入元素,对应键值对
    jObj.insert("m_isAssignCenterEdge", m_isAssignCenterEdge);
    jObj.insert("m_measureWidth", m_measureWidth);
    jObj.insert("m_measureHeight", m_measureHeight);  
    return QJsonValue(jObj);
  }       
};

3、将本地Json数据进行反序列化成结构体中的数据(fromJson — 解析数据),

struct MS_EdgeLineFitParam
{
   //初始化结构体内数据
  MS_EdgeLineFitParam()
  {
    m_isAssignCenterEdge= false;
    m_measureWidth= 5;
    m_dMeasureHeight = 0.0;
  }
  bool   m_isAssignCenterEdge;     
  int    m_measureWidth;           
  double m_measureHeight;   
  //将本地`Json`数据进行反序列化成结构体中的数据
  static MS_EdgeLineFitParam fromJson(QJsonValue _json)
  {
    MS_EdgeLineFitParam task;
    //定义空对象
    QJsonObject jObj = _json.toObject();
    //将Json类型数据进行反序列化
    task.m_isAssignCenterEdge= jObj.value("m_isAssignCenterEdge").toBool();
    task.m_measureWidth= jObj.value("m_measureWidth").toInt();
    task.m_measureHeight= jObj.value("m_measureHeight").toDouble();   
    return task;
  }     
};

四. QJson库读、存数据的完整代码操作

1、结构体数据类型的序列化与反序列化

enum ME_EdgeLineFitShape
{
  EDGELINE_LINE = 0,
};
struct MS_IntersectionParam
{
  MS_IntersectionParam()
  {
    m_intersectionEdgeOne = 0;
  }
  int m_intersectionEdgeOne;
  static MS_IntersectionParam fromJson(QJsonValue _json)
  {
    MS_IntersectionParam task;
    QJsonObject jObj = _json.toObject();
    task.m_intersectionEdgeOne = jObj.value("m_intersectionEdgeOne").toInt();
    return task;
  }
  QJsonValue toJson()
  {
    QJsonObject jObj;
    jObj.insert("m_intersectionEdgeOne", m_intersectionEdgeOne);
    return QJsonValue(jObj);
  }
};
struct MS_EdgeLineFitParam
{
   //初始化结构体内数据
  MS_EdgeLineFitParam()
  {
    m_isAssignCenterEdge= false;
    m_measureWidth= 5;
    m_dMeasureHeight = 0.0;
  }
  bool   m_isAssignCenterEdge;     
  int    m_measureWidth;           
  double m_measureHeight; 
  ME_EdgeLineFitShape  m_edgeLineFitShape;  //自定义的枚举   ME_EdgeLineFitShape  
  MS_IntersectionParam m_intersectionParam; //自定义的结构体 MS_IntersectionParam 
    static MS_EdgeLineFitParam fromJson(QJsonValue _json)
  {
    MS_EdgeLineFitParam task;
    QJsonObject jObj = _json.toObject();
    task.m_isAssignCenterEdge = jObj.value("m_isAssignCenterEdge").toBool();
    task.m_measureWidth = jObj.value("m_measureWidth").toInt();
    task.m_measureHeight = jObj.value("m_measureHeight").toDouble();
    //fromJson中自定义的枚举的写法
    task.m_edgeLineFitShape = (ME_EdgeLineFitShape)jObj.value("m_edgeLineFitShape").toInt();
    //fromJson中自定义结构体的写法
    task.m_intersectionParam = MS_IntersectionParam::fromJson(jObj.value("m_intersectionParam"));   
    return task;
  }
  QJsonValue toJson()
  {
    QJsonObject jObj;
    jObj.insert("m_isAssignCenterEdge", m_isAssignCenterEdge);
    jObj.insert("m_measureWidth", m_measureWidth);
    jObj.insert("m_measureHeight", m_measureHeight);
    //toJson中自定义的枚举的写法和常规写法一致
    jObj.insert("m_edgeLineFitShape", m_edgeLineFitShape);
    //toJson中自定义结构体的写法
    jObj.insert("m_intersectionParam", m_intersectionParam.toJson()); 
    return QJsonValue(jObj);
  }
};
struct VISIONLIBRARY_API MS_EdgeLineFit
{
    //输出结构体包含的数据类型map,bool
    std::map<int, MS_EdgeLineFitParam>  m_edgeLineFitParam;
    bool m_isAffineContour = true;
    //解析、读取保存到的本地数据
    static MS_EdgeLineFit fromJson(QJsonValue _json)
  {
    MS_EdgeLineFit task;
    QJsonObject jObj = _json.toObject();
    task.m_name = QString(jObj.value("m_name").toString().toLocal8Bit());
        //fromJson中自定义map的写法
    QJsonArray edgeLineFitParam = jObj.value("m_edgeLineFitParam").toArray();
    for (auto value : edgeLineFitParam)
    {
      QJsonArray jArr = value.toArray();
      int num = jArr[0].toInt();
      MS_EdgeLineFitParam fitParam = MS_EdgeLineFitParam::fromJson(jArr[1]);
      task.m_edgeLineFitParam.insert(std::map<int, MS_EdgeLineFitParam>::value_type(num, fitParam));
    }
    task.m_isAffineContour = jObj.value("m_isAffineContour").toBool();
    return task;
  }
  //结构体数据通过toJson转换保存本地
  QJsonValue toJson()
  {
    QJsonObject jObj;
    jObj.insert("task_name", m_name);
    std::map<int, MS_EdgeLineFitParam>::iterator fitParamIter;
    QJsonArray fitParamJArr;
    for (fitParamIter = m_edgeLineFitParam.begin(); fitParamIter != m_edgeLineFitParam.end(); fitParamIter++)
    {
      QJsonArray jArr;
      jArr.append(fitParamIter->first);
      jArr.append(fitParamIter->second.toJson());
      fitParamJArr.append(jArr);
    }
    jObj.insert("m_edgeLineFitParam", fitParamJArr);
    jObj.insert("m_isAffineContour", m_isAffineContour);
    return QJsonValue(jObj);
  }
};
Q_DECLARE_METATYPE(MS_EdgeLineFit)

2、读、存QJson生成的.json文件

MS_EdgeLineFit::MS_EdgeLineFit(const QString& _name)
{ 
  m_name = _name;
  m_edgeLineFitPath = "./VisionFiles/EdgeLineFit/" + m_name + "/";
  read();
}
bool MS_EdgeLineFit::read()
{
  QDir traDir(m_edgeLineFitPath);
  if (!traDir.exists()) {
    ERROR_VISION("read attachData faild due to no such directory!");
    return true;
  }
  QString fileName = QString(m_edgeLineFitPath + "attachData.json").toStdString().c_str();
  INFO_VISION("read attachData taskPath, %s", fileName.toStdString().c_str());
  QFileInfo cfg_json(fileName);
  if (!cfg_json.exists())
  {
    INFO_VISION("read attachData faild due to no such file!");
    return false;
  }
  QFile file_json(fileName);
  if (!(file_json.open(QIODevice::ReadOnly | QIODevice::Text)))
  {
    INFO_VISION("read attachData faild due to file cannot be opened!");
    return false;
  }
  QByteArray cfgContent = file_json.readAll();
  file_json.close();
  QJsonParseError jsonError;
  QJsonDocument jsonDoc = QJsonDocument::fromJson(cfgContent, &jsonError);
  if (!jsonDoc.isNull() && (jsonError.error == QJsonParseError::NoError) && jsonDoc.isObject())
  {   
    INFO_VISION("read attachData success, %s", fileName.toStdString().c_str());
    QJsonObject jObj = jsonDoc.object();
    MS_EdgeLineFit task = MS_EdgeLineFit::fromJson(jObj.value("Task"));
    m_edgeLineFitParam = task.m_edgeLineFitParam;
    m_isAffineContour = task.m_isAffineContour;
    return true;
  }
  else
  {
    INFO_VISION("read attachData faild due to attachData exception!");
    return false;
  }
}
bool MS_EdgeLineFit::write()
{
  writeGraphic();
  QString fileName = QString(m_edgeLineFitPath + "attachData.json").toStdString().c_str();
  INFO_VISION("write attachData taskPath, %s", fileName.toStdString().c_str());
  QJsonDocument doc;
  QJsonObject jObj;  
  MS_EdgeLineFit task(m_name);
  task.m_edgeFitHRegion = m_edgeFitHRegion;
  task.m_isAffineContour = m_isAffineContour;
  jObj.insert("Task", task.toJson());
  doc.setObject(jObj);
  QString jsonText = doc.toJson();
  QFile cfgFile(fileName);
  if (!(cfgFile.open(QIODevice::WriteOnly | QIODevice::Text)))
  {
    ERROR_VISION("Error occured in write attachData fail due to file cannot be opened!");
    return false;
  }
  cfgFile.write(jsonText.toStdString().data());
  cfgFile.close();
  return true;
}

五. 总结

本文主要对结构体中数据类型使用QJson库的方式进行读存,数据类型包括boolintdoubleenummap等,以及结构体内嵌套子结构体情况下的处理。


下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。


目录
相关文章
|
5月前
|
Linux iOS开发 开发者
Qt问题(二):无法定位程序输入点于动态链接库
动态链接库(Dynamic Link Library,简称DLL)是一种可执行文件格式,常见于Windows操作系统中,而在Linux和macOS等其他操作系统中,相似的概念通常被称为共享库(Shared Library)。动态链接库允许程序在运行时加载所需的代码和数据,而不是在编译时静态链接到应用程序中。这种方式带来了几个重要的优点:
526 3
|
4月前
|
存储 C++
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
112 1
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
|
5月前
|
Oracle 关系型数据库 Linux
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
通过这一连串的步骤,可以专业且有效地在Linux下为Qt编译Oracle驱动库 `libqsqloci.so`,使得Qt应用能够通过OCI与Oracle数据库进行交互。这些步骤适用于具备一定Linux和Qt经验的开发者,并且能够为需要使用Qt开发数据库应用的专业人士提供指导。
181 1
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
|
4月前
|
API 开发工具 C语言
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
248 0
|
6月前
|
存储 编解码 Ubuntu
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
|
6月前
Cmake构建Qt项目链接glog库
Cmake构建Qt项目链接glog库
|
7月前
|
编解码
qt中使用dll库的方法
qt中使用dll库的方法
109 2
|
7月前
|
JSON 网络协议 开发工具
基于Qt实现的TCP端口数据转发服务器
基于Qt实现的TCP端口数据转发服务器
84 0
基于Qt实现的TCP端口数据转发服务器
|
7月前
|
存储
Qt更新组件出现(“要继续此操作,至少需要一个有效且已启用的储存库”)
Qt更新组件出现(“要继续此操作,至少需要一个有效且已启用的储存库”)
401 0
Qt更新组件出现(“要继续此操作,至少需要一个有效且已启用的储存库”)
|
7月前
|
编译器
正点原子IMX6ULL-安装交叉编译器、编译tslib触摸屏库、编译arm环境qt源代码
正点原子IMX6ULL-安装交叉编译器、编译tslib触摸屏库、编译arm环境qt源代码
245 0