jsoncpp的安装与使用

一个小工程需要在C++中使用json,于是我找到了库jsoncpp。第一次在Visual Studio中安装和使用jsoncpp库的时踩了一些坑,花了半天的时间解决了问题。写一篇博客来分享jsoncpp的安装与使用方法。

安装

写在开始之前

我的jsoncpp库的版本:jsoncpp-1.8.4

示例项目的名称:jsontest

路径:D:\proj\jsoncppTEST\

必看!必看!必看!

安装过程中将会用到git bash

在安装jsoncpp之前,确保你的Visual Studio安装了英文语言包,否则最后一步将会无法执行。如果没有安装英文语言包,请在Visual Studio修改程序(在程序和功能里面找)里面添加这个语言包。

直接在github上下载jsoncpp,然后想百(CS)度(DN)上说的那样去做是没法成功的。

那么百(CS)度(DN)上怎么说的?

首先下载jsoncpp这个库

打开jsoncpp\makefiles\vs71\jsoncpp.sln,然后编译以生成json_vc71_libmtd.lib(工程把json_vc71_libmtd.lib生成到了jsoncpp\build\vs71\debug\lib_json下)

然后把jsoncpp\include\json\下的文件以及json_vc71_libmtd.lib复制到工程目录下

把这些文件添加到工程中,并且修改项目属性,修改方法为balabalabalabala…

然后就大功告成

如果这样做,那么恭喜你,VS会亲切地告诉你:

jsoncpp的安装与使用-亲切地告诉你.png

(当然这里使用的是另一个项目)

开始安装

根据github上的jsoncpp库的官方说明文档README.md,首先我们打开(或者新建一个)VS项目,然后在终端打开

jsoncpp的安装与使用-在终端打开.png

接着我们会发现左下角多了一个选项卡:开发者PowerShell

jsoncpp的安装与使用-开发者PowerShell.png

现在我们在Powershell里面依次执行以下命令(一条一条复制上去然后一条一条运行):

1
2
3
4
5
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install jsoncpp

这里再写一遍:如果你的Visual Studio没有安装英文语言包,那么请在Visual Studio修改程序(在程序和功能里面找)里面添加这个语言包。

这样就可以了,是不是很简单啊(不枉费我半天时间)

使用

关于json

json诞生自js,因为二者十分相似,所以相互支持起来非常方便。不过我们在C++中也需要使用json,所以又有大佬专门为C++开发了jsoncpp

json的食用方法

json中仅支持两种结构

  • name->value,键值对(pair)的集合,一般称为对象(object)
  • 值的有序表,一般称为数组(array)

键值对pair

一个pair的结构通常是:string : value,pair的对应关系用:表示,左边的为name,右边的是其对应的值value

一般key使用字符串。也可以使用数字,但是不推荐

value可以是json支持的任何类型,如object、array、string、number、true/false,null

对象object

object可以认为是多个pair的集合,其语法为

  • {作为object起始
  • }作为object结束
  • 不同pair之间使用,分割

object中存储的数据是无序的

例如:

1
2
3
4
{
"name": "jensentsts",
"score": 114514
}

数组array

array是value的有序集合,其语法为

  • [作为array起始
  • ]作为array结束
  • 不同array元素之间使用,分割

建议在array中使用统一的类型,否则解析起来比较麻烦

例如:

1
[{"name": "jensentsts", "score": 114514}, {"name": "LiHua", "score": -1}]

当然这样写也是合法的:

1
["jensentsts", 233, null, {"year": 1919810}, false]

注释

与C++一样,使用//或者是/**/来写注释

例如:

1
2
// 衬衫的价格为
/* 9镑15便士 */

全部加起来,结果写出来

例如(这是我的VS Code配置):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// https://code.visualstudio.com/docs/cpp/launch-json-reference
{
"version": "0.2.0",
"configurations": [{
"name": "(gdb) Launch", // 配置名称,将会在启动配置的下拉菜单中显示
"type": "cppdbg", // 配置类型,对于C/C++可认为此处只能是cppdbg,由cpptools提供;不同编程语言不同
"request": "launch", // 可以为launch(启动)或attach(附加)
"program": "${fileDirname}/${fileBasenameNoExtension}.exe", // 将要进行调试的程序的路径
"args": [], // 程序调试时传递给程序的命令行参数,一般设为空
"stopAtEntry": false, // 设为true时程序将暂停在程序入口处,相当于在main上打断点
"cwd": "${workspaceFolder}", // 调试程序时的工作目录,此为工作区文件夹;改成${fileDirname}可变为文件所在目录
"environment": [], // 环境变量
"externalConsole": true, // 使用单独的cmd窗口,与其它IDE一致;为false时使用内置终端
"internalConsoleOptions": "neverOpen", // 如果不设为neverOpen,调试时会跳到“调试控制台”选项卡,你应该不需要对gdb手动输命令吧?
"MIMode": "gdb", // 指定连接的调试器,可以为gdb或lldb。但我没试过lldb
"miDebuggerPath": "gdb.exe", // 调试器路径,Windows下后缀不能省略,Linux下则不要
"setupCommands": [
{ // 模板自带,好像可以更好地显示STL容器的内容,具体作用自行Google
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": false
}
],
"preLaunchTask": "Compile" // 调试前执行的任务,一般为编译程序。与tasks.json的label相对应
}]
}

jsoncpp头文件

使用jsoncpp的任何功能,只需要引入一个头文件就好:

1
#include <json/json.h>

JSON解析

解析json字符串

我们将会使用Json::Reader来解析JSON数据,用Json::Value来存储JSON解析出来的各种值。

Json::Reader reader;然后调用reader.parse()解析JSON数据。如果解析成功,返回false;否则返回true

我们将要处理的json数据:

1
{"name": "jensentsts", "score": 114514}

示例代码:

1
2
3
4
5
6
7
8
9
10
11
Json::Reader reader;
Json::Value root;
std::string jsonString = "{\"name\": \"jensentsts\", \"score\": 114514}";
if (reader.parse(jsonString/*或者jsonString.c_str()*/, root)){
std::cerr << "parse failed!" << std::endl;
}
else{
// 类型一定要正确选择,否则会抛出异常
std::cout << root["name"].asString() << std::endl; // 选择为string类型并输出
std::cout << root["score"].asInt() << std::endl; // 选择为int类型并输出
}

当然了,还可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
Json::Reader reader;
Json::Value root;
const char jsonString[] = "{\"name\": \"jensentsts\", \"score\": 114514}";
if (!reader.parse(jsonString, jsonString + sizeof(jsonString), root)){
// 这样就是在字符串之中读取部分文本并且解析
// 类型一定要正确选择,否则会抛出异常
std::cout << root["name"].asString() << std::endl; // 选择为string类型并输出
std::cout << root["score"].asInt() << std::endl; // 选择为int类型并输出
}
else{
std::cerr << "parse failed!" << std::endl;
}

同样的输出结果:

1
2
jensentsts
114514

从json文件中读取并解析

以下代码修改自参考资料1

1
2
3
4
5
// "checkjson.json"中的数据
{
"name" : "tocy",
"age" : 1000
}

下面的代码将其读入并解析

1
2
3
4
5
6
7
8
9
10
11
ifstream ifs("checkjson.json");
assert(ifs.is_open());
Json::Reader reader;
Json::Value root;
if (reader.parse(ifs, root, false)){
std::cerr << "parse failed!" << std::endl;
}
else{
std::string name = root["name"].asString();
int age = root["age"].asInt();
}

解析array数据

我们将要解析的json数据:

1
2
3
4
[
{ "name": "Tony", "salary": 100 },
{ "name": "Kit", "salary": 233}
]

示例代码:

1
2
3
4
5
6
7
8
9
10
11
std::string json = "[\"Here is data below.\", {\"Tony\": \"\", \"salary\": 100}, {\"name\": \"Kit\", \"salary\": 233}]"
Json::Reader reader;
Json::Value root;
if (!reader.parse(json, root)){
// 在json中,第一项是string,第二、三项是object,下面我们将分别输出它们
std::cout << root[0] << std::endl;
size_t count = root.size();
for (size_t i = 1; i < count; ++i){
std::cout << root[i]["name"].asString() << "\'s salary is " << root[i]["salary"].asInt() << "." << std::endl;
}
}

输出结果:

1
2
3
Here is data below.
Tony's salary is 100.
Kit's salary is 233.

全部加起来,结果写出来

我们将要解析的json数据(放在了jkl.json中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"package-name": "jinkela",
"version": "1.0.0",
"artists":[
{ "name": "Mei", "from": "America" },
{ "name": "Ri", "from": "Japan" },
{ "name": "Fei", "from": "Aferica"}
],
"prop": {
"name": "jinkela",
"kind": "fertilizer",
"cost": 450,
}
}

__ __ __ __:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void packageInstaller(){
Json::Reader reader;
Json::Value root;
ifstream ifs("jkl.json");
if (!ifs.is_open()){
std::cerr << "Cannot open the file." << std::endl;
return;
}
if (reader.parse(ifs, root)){
std::cerr << "Failed to parse JSON." << std::endl;
return;
}
std::clog << "Stage Package Installer loaded." << std::endl;
std::clog << "Package name: " << root["package-name"].asString() << std::endl;
std::clog << "Package version: " << root["version"].asString() << std::endl;
size_t count = root["artists"].size();
// "artists"
for (size_t i = 0; i < count; ++i){
std::clog << "Artist " << i << "is " << root["artists"][i]["name"].asString() << std::endl;
std::clog << "\twho is from " << root["artists"][i]["from"].asString() << std::endl;
}
// "prop"
Json::Value prop = root["prop"];
std::clog << "The prop they need:" << std::endl;
std::clog << "name: " << prop["name"].asString() << std::endl;
std::clog << "kind: " << prop["kind"].asString() <<std::endl;
std::clog << "cost: " << prop["cost"].asInt() << std::endl;
}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
Stage Package Installer loaded.
Package name: jinkela
Package version: 1.0.0
Artist 0is Mei
who is from America
Artist 1is Ri
who is from Japan
Artist 2is Fei
who is from Aferica
The prop they need:
name: jinkela
kind: fertilizer
cost: 450

小结

解析操作基本上就是这些。

我们通过Json::Reader对象中的parse()解析JSON数据,parse()会自动地吧结果写入传入的Json::Value对象中。调用parse()的方法有很多种,一般来说分别是:

  • parse(C++ stream, Json::Value),第一项可以是string,也可以是ifstream
  • parse(const char* begin, const char* end, Json::Value)
  • parse(const char* str, Json::Value)

总之最后一项是Json::Value。你可能会发现parse()的最后一项会是collectComments,这个我还没研究过,咕咕咕(*・ω< )

Json::Value对象中存储的可能是一个键值对,object,array,也可能只是一个简简单单的string,Number,Boolean等等,我们要通过Json::Value对象.as***()以在C++中使用他们的值

在示例代码中,我们创建了一个名为root的变量,并用root存储JSON数据的“根节点”。在“全部加起来,结果写出来”中,我们也用了一个Json::Value prop来存储其“子节点”的信息。并通过prop来访问其下的数据。其实,只要我们调用的不是as***(),那么我们得到的对象都是Json::Value类型的

JSON数据封装

这里我们会用Json::Value来存储JSON中的数据,然后用Json::Writer来把编辑好的Json::Value转换为JSON字符串

封装简单的数据

示例代码:

1
2
3
4
5
6
7
8
9
10
11
Json::Value root;
Json::Value files;
Json::FastWriter writer;
root["name"] = "Tony";
root["salary"] = 100;
root["msg"] = "work hard";
files[0] = "1.zip";
files[1] = "2.txt";
root["files"] = files;
std::string jsonFile = writer.write(root);
std::cout << jsonFile << std::endl;

封装内嵌object的array

其实和上边那个例子的过程一样。只要你能明白两点

  • 对着Json::Value对象直接去赋值
  • array和object的调用方法和使用方法大差不差

咕咕咕

参考资料

  1. json简介及JsonCpp用法
  2. github上jsoncpp/README.md
  3. 百度得到的CSDN博客
作者

勇敢梧桐树

发布于

2022-02-02

更新于

2023-01-04

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×