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

目录:

  • 一. Boost库介绍
  • 二. QJson库介绍
  • 三. QJson库生成与解析结构体数据
  • 四. QJson库读、存数据的完整代码操作

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(Qt实战项目视频教程+代码,C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

一. 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、包含头文件:

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库的方式进行读存,数据类型包括bool、int、double、enum、map等,以及结构体内嵌套子结构体情况下的处理。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(Qt实战项目视频教程+代码,C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓