JsonCpp
参考文档:https://zhuanlan.zhihu.com/p/374319504
json是一种轻量级数据交换格式,易于阅读和编写,也易于机器解析和生成。使用json格式可以方便地在各个系统之间传递数据。在c++中,有许多开源的json库可以进行json的处理。比如:RapidJSON 、Boost.PropertyTree实现、 JsonCpp实现、Nlohmann.Json实现。本文将介绍JsonCpp开源库的json处理方法及实现。
JSON(JavaScript Object Notation) 是Douglas crockford于21世纪初指定的一种轻量级的数据交换格式,既易于人们阅读和编写,也易于机器的解析和生成。尽管JSON是JavaScript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯,因此其成为了理想的数据交换语言。
本篇主要讲解了使用C++语言对JSON文件进行的操作,包括环境配置、文件读取、文件写入。
一、环境配置
(一)jsoncpp库的下载
本文选择一个第三方库 jsoncpp 来解析 JSON。jsoncpp 是比较出名的 C++ JSON 解析库。在 JSON 官网也是首推的。
下载地址为:http://sourceforge.net/projects/jsoncpp。本文使用的 jsoncpp 版本为:0.5.0。
(二)基于Visual Studio2015的环境配置
这个老版本的配置方式较为简单,只需要添加相应的头文件即可。
(1)将文件中的include和src文件夹拷贝到vs工程的目录下。
(2)在工程属性栏附加包含目录中添加include的路径。
(3)在工程“源文件”添加上述src下lib_json下的cpp文件。
二、写入文件
这里我们先给出整体代码,输出结果如本篇开始所示,我们主要介绍基于类似于c++“map”的方式(以后简称map)和父子节点的形式。
#include <iostream>
#include <fstream>
#include <json/json.h>
using namespace std;
int main() {
//根节点
Json::Value root;
//若直接使用“=”进行赋值,则默认该变量:为一个数或字符串
root["Group Name"] = "Togehter"; //1.根节点"Group Name"和值"Togehter"
root["Number"] = 2; //2.根节点"Number"和值2
//若使用“append”则默认该变量:为向量的形式
//3.根节点"Students"和值{"Zhangsan":[180,70], "Lisi":[165,50]}
//3.1 Map形式
root["Students"]["Zhangsan"].append(180);
root["Students"]["Zhangsan"].append(70);
root["Students"]["Lisi"].append(165);
root["Students"]["Lisi"].append(50);
//3.2父子节点形式
Json::Value student;
student["Zhangsan"].append(180);
student["Zhangsan"].append(70);
student["Lisi"].append(165);
student["Lisi"].append(50);
root["Students"] = student;
//格式化输出到文件
ofstream os; //实例化输出类
os.open("test.json", std::ios::out); //打开并指定文件以输出方式打开(往文件里写)
if (!os.is_open()) //检查文件打开情况
cout << "open file failed" << endl;
Json::StyledWriter sw; //定义格式化输出
os << sw.write(root); //输出到文件
os.close(); //关闭文件
return 0;
}
1. 首先定义根节点,针对一级子对象可以直接使用map的形式进行操作,这里若直接使用“=”进行赋值,则默认该变量为一个数或字符串;若使用“append”则默认该变量为向量的形式。
Json::Value root;
root["Group Name"] = "Togehter";
root["Number"] = 2;
2. 针对含有二级对象的内容,可以使用以下两种方式:
(1)map形式,这种方式较为简单,但缺点就是只能处理相对比较简单的二级对象。
在一级对象后直接跟不同的二级对象作为区分,并针对二级对象进行赋值或添加的操作。
root["Students"]["Zhangsan"].append(180); //添加身高信息
root["Students"]["Zhangsan"].append(70); //添加体重信息
root["Students"]["Lisi"].append(165); //添加身高信息
root["Students"]["Lisi"].append(50); //添加体重信息
(2)父子节点的形式,缺点就是定义起来较为麻烦。
定义子节点,然后按照与根节点相同的方式对子节点进行处理,最后将其链接到根节点即可。
Json::Value student; //定义子节点
student["Zhangsan"].append(180);
student["Zhangsan"].append(70);
student["Lisi"].append(165);
student["Lisi"].append(50);
root["Students"] = student; //将子节点链接到根节点上
写入的Json文件格式如下:
三、读取文件
读取文件较为简单,这里就不展开详细讲解啦,大家可以参考下面的注释,上整体代码。
#include <iostream>
#include <fstream>
#include <json/json.h>
using namespace std;
int main() {
Json::Reader reader;
Json::Value root;
ifstream is("test.json", ios::binary); //打开文件,以二进制方式打开文件
if (!is.is_open()) //检查文件打开情况
cout << "open file failed" << endl;
if (reader.parse(is, root)) {
//读取根节点信息
string group_name = root["Group Name"].asString();
int number = root["Number"].asInt();
cout << "Group Name: " << group_name << endl;
cout << "Number: " << number << endl;
//读取子节点信息
int body[2]; //身高、体重
/********注意遍历json数组的时候要使用unsigned int的变量********/
body[0] = root["Students"]["Zhangsan"][(unsigned int)0].asInt();
body[1] = root["Students"]["Zhangsan"][(unsigned int)1].asInt();
cout << "Zhangsan height:" << body[0] << " weight: " << body[1] << endl;
body[0] = root["Students"]["Lisi"][(unsigned int)0].asInt();
body[1] = root["Students"]["Lisi"][(unsigned int)1].asInt();
cout << "Lisi height:" << body[0] << " weight: " << body[1] << endl;
}
is.close();
return 0;
}
最后输出的结果如下图所示:
四、xml和json文件对比
1、xml如下:
2、如何用json来写此文件
#include <iostream>
#include <fstream>
#include <json/json.h>
using namespace std;
int main() {
//根节点
Json::Value root;
//若直接使用“=”进行赋值,则默认该变量:为一个数或字符串
root["CTHost Version"] = "1.00";
root["LastModifyTime"] = "2024.11.14 17:29 : 00"; //1.根节点"Group Name"和值"Togehter"
//若使用“append”则默认该变量:为向量的形式
//3.根节点"Students"和值{"Zhangsan":[180,70], "Lisi":[165,50]}
//3.1 Map形式
root["Options"]["DeviceName"].append("AD90");
root["Options"]["AutoConnectEngine"].append(1);
root["Options"]["EngineTimeout"].append(60);
root["Options"]["RemoteDir"].append("C:\\Host\\Config\\HOST alarm\\");
root["Options"]["EngineIP"].append("127.0.0.1");
//点
root["TypePointCount"] = 2;
root["TypePoint0"]["Type"] = "0";
root["TypePoint0"]["PsTypePoint"]["PsType"]["IsValid"] = 0;
root["TypePoint0"]["PsTypePoint"]["PsType"]["IsCompareWith1"] = 0;
root["TypePoint0"]["PsTypePoint"]["PsType"]["Name"] = "OtPoint";
root["TypePoint0"]["PsTypePoint"]["PsType"]["Code"] = "OTP";
root["TypePoint0"]["PsTypePoint"]["PsGrade0"]["CountEnable"] = 0;
root["TypePoint0"]["PsTypePoint"]["PsGrade0"]["CountMin"] = 0;
root["TypePoint0"]["PsTypePoint"]["PsGrade0"]["CountMinCountMax"] = 0;
root["TypePoint0"]["PsTypePoint"]["PsGrade1"]["CountEnable"] = 1;
root["TypePoint0"]["PsTypePoint"]["PsGrade1"]["CountMin"] = 0;
root["TypePoint0"]["PsTypePoint"]["PsGrade1"]["CountMinCountMax"] = 1;
root["TypePoint1"]["Type"] = "0";
root["TypePoint1"]["PsTypePoint"]["PsType"]["IsValid"] = 0;
root["TypePoint1"]["PsTypePoint"]["PsType"]["IsCompareWith1"] = 0;
root["TypePoint1"]["PsTypePoint"]["PsType"]["Name"] = "OtPoint";
root["TypePoint1"]["PsTypePoint"]["PsType"]["Code"] = "OTP";
root["TypePoint1"]["PsTypePoint"]["PsGrade0"]["CountEnable"] = 0;
root["TypePoint1"]["PsTypePoint"]["PsGrade0"]["CountMin"] = 0;
root["TypePoint1"]["PsTypePoint"]["PsGrade0"]["CountMinCountMax"] = 0;
root["TypePoint1"]["PsTypePoint"]["PsGrade1"]["CountEnable"] = 1;
root["TypePoint1"]["PsTypePoint"]["PsGrade1"]["CountMin"] = 0;
root["TypePoint1"]["PsTypePoint"]["PsGrade1"]["CountMinCountMax"] = 1;
//线
root["TypeLineCount"] = 2;
root["TypeLine0"]["Type"] = "0";
root["TypeLine0"]["TypeLine"]["PsType"]["IsValid"] = 0;
root["TypeLine0"]["TypeLine"]["PsType"]["IsCompareWith1"] = 0;
root["TypeLine0"]["TypeLine"]["PsType"]["Name"] = "OtLine";
root["TypeLine0"]["TypeLine"]["PsType"]["Code"] = "OTEP";
root["TypeLine0"]["TypeLine"]["PsGrade0"]["CountEnable"] = 0;
root["TypeLine0"]["TypeLine"]["PsGrade0"]["CountMin"] = 0;
root["TypeLine0"]["TypeLine"]["PsGrade0"]["CountMinCountMax"] = 0;
root["TypeLine0"]["TypeLine"]["PsGrade1"]["CountEnable"] = 1;
root["TypeLine0"]["TypeLine"]["PsGrade1"]["CountMin"] = 0;
root["TypeLine0"]["TypeLine"]["PsGrade1"]["CountMinCountMax"] = 1;
root["TypeLine1"]["Type"] = "0";
root["TypeLine1"]["TypeLine"]["PsType"]["IsValid"] = 0;
root["TypeLine1"]["TypeLine"]["PsType"]["IsCompareWith1"] = 0;
root["TypeLine1"]["TypeLine"]["PsType"]["Name"] = "OtLine";
root["TypeLine1"]["TypeLine"]["PsType"]["Code"] = "OTEP";
root["TypeLine1"]["TypeLine"]["PsGrade0"]["CountEnable"] = 0;
root["TypeLine1"]["TypeLine"]["PsGrade0"]["CountMin"] = 0;
root["TypeLine1"]["TypeLine"]["PsGrade0"]["CountMinCountMax"] = 0;
root["TypeLine1"]["TypeLine"]["PsGrade1"]["CountEnable"] = 1;
root["TypeLine1"]["TypeLine"]["PsGrade1"]["CountMin"] = 0;
root["TypeLine1"]["TypeLine"]["PsGrade1"]["CountMinCountMax"] = 1;
3.2 父子节点形式
//Json::Value student;
//student["Zhangsan"].append(180);
//student["Zhangsan"].append(70);
//student["Lisi"].append(165);
//student["Lisi"].append(50);
//root["Students"] = student;
//格式化输出到文件
ofstream os; //实例化输出类
os.open("Option.json", std::ios::out); //打开并指定文件以输出方式打开(往文件里写)
if (!os.is_open()) //检查文件打开情况
cout << "open file failed" << endl;
Json::StyledWriter sw; //定义格式化输出
os << sw.write(root); //输出到文件
os.close(); //关闭文件
return 0;
}
结果: