文章目录
- 1.Json基础知识
- 2.安装JsonCpp
- 3.jsoncpp的使用
1.Json基础知识
Json 中主要有两种数据格式:Json 数组和 Json 对象,并且这两种格式可以交叉嵌套使用
Json 数组
Json 数组使用 [] 表示,[] 里边是元素,元素和元素之间使用逗号间隔,最后一个元素后边没有逗号,一个 Json 数组中支持同时存在多种不同类型的成员,包括:整形、 浮点、 字符串、 布尔类型、 json数组、 json对象、 空值-null。由此可见 Json 数组比起 C/C++ 数组要灵活很多。
- Json 数组中的元素数据类型一致
// 整形
[1,2,3,4,5]
// 字符串
["luffy", "sanji", "zoro", "nami", "robin"]
- Json 数组中的元素数据类型不一致
[12, 13.34, true, false, "hello,world", null]
- Json 数组中的数组嵌套使用
[
["cat", "dog", "panda", "beer", "rabbit"],
["北京", "上海", "天津", "重庆"],
["luffy", "boy", 19]
]
- Json 数组和对象嵌套使用
[
{
"luffy":{
"age":19,
"father":"Monkey·D·Dragon",
"grandpa":"Monkey D Garp",
"brother1":"Portgas D Ace",
"brother2":"Sabo"
}
}
]
Json 对象
- Json 对象使用 {} 来描述,每个 Json 对象中可以存储若干个元素,每一个元素对应一个键值对(key:value 结构),元素和元素之间使用逗号间隔,最后一个元素后边没有逗号。对于每个元素中的键值对有以下细节需要注意:
键值(key)必须是字符串,位于同一层级的键值不要重复(因为是通过键值取出对应的 value 值)
value 值的类型是可选的,可根据实际需求指定,可用类型包括:整形、 浮点、 字符串、 布尔类型、 json数组、 json对象、 空值-null。
- 使用 Json 对象描述一个人的信息:
{
"Name":"Ace",
"Sex":"man",
"Age":20,
"Family":{
"Father":"Gol·D·Roger",
"Mother":"Portgas·D·Rouge",
"Brother":["Sabo", "Monkey D. Luffy"]
},
"IsAlive":false,
"Comment":"yyds"
}
注意事项
- 在一个 Json 文件中只能有一个 Json 数组或者 Json 对象的根节点,不允许同时存储多个并列的根节点。
- 错误的写法
// test.json
{
"name":"luffy",
"age":19
}
{
"user":"ace",
"passwd":"123456"
}
错误原因:在一个 Json 文件中有两个并列的 Json 根节点(并列包含 Json 对象和 Json 对象、Json 对象和 Json 数组、Json 数组和 Json 数组),根节点只能有一个。
- 正确的写法
// test.json
{
"Name":"Ace",
"Sex":"man",
"Age":20,
"Family":{
"Father":"Gol·D·Roger",
"Mother":"Portgas·D·Rouge",
"Brother":["Sabo", "Monkey D. Luffy"]
},
"IsAlive":false,
"Comment":"yyds"
}
- ref:Json,Json以及Json在Qt中的使用 【Qt/C/C++】
2.安装JsonCpp
开发环境ubuntu
sudo apt-get install libjsoncpp-dev
3.jsoncpp的使用
jsoncpp 库中的类被定义到了一个 Json 命名空间中,建议在使用这个库的时候先声明这个命名空间:
using namespace Json;
使用 jsoncpp 库解析 json 格式的数据,我们只需要掌握三个类:
Value 类:将 json 支持的数据类型进行了包装,最终得到一个 Value 类型
FastWriter类:将 Value 对象中的数据序列化为字符串
Reader类:反序列化,将 json 字符串 解析成 Value 类型
Value 类
- 这个类可以看做是一个包装器,它可以封装 Json 支持的所有类型,这样我们在处理数据的时候就方便多了。
枚举类型 说明 翻译
nullValue | ‘null’ value | 不表示任何数据,空值 |
intValue | signed integer value | 表示有符号整数 |
uintValue | unsigned integer value | 表示无符号整数 |
realValue | double value | 表示浮点数 |
stringValue | UTF-8 string value | 表示 utf8 格式的字符串 |
booleanValue | bool value | 表示布尔数 |
arrayValue | array value (ordered list) | 表示数组,即 JSON 串中的 [] |
objectValue | object value (collection of name/value pairs) | 表示键值对,即 JSON 串中的 {} |
– | – | – |
构造函数
- Value 类为我们提供了很多构造函数,通过构造函数来封装数据,最终得到一个统一的类型。
// 因为Json::Value已经实现了各种数据类型的构造函数
Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
Value(Int64 value);
Value(UInt64 value);
Value(double value);
Value(const char* value);
Value(const char* begin, const char* end);
Value(bool value);
Value(const Value& other);
Value(Value&& other);
检测保存的数据类型
// 检测保存的数据类型
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
将 Value 对象转换为实际类型
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
JSONCPP_STRING asString() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
const char* asCString() const;
对 json 数组的操作
ArrayIndex size() const;
Value& operator[](ArrayIndex index);
Value& operator[](int index);
const Value& operator[](ArrayIndex index) const;
const Value& operator[](int index) const;
// 根据下标的index返回这个位置的value值
// 如果没找到这个index对应的value, 返回第二个参数defaultValue
Value get(ArrayIndex index, const Value& defaultValue) const;
Value& append(const Value& value);
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
对 json 对象的操作
Value& operator[](const char* key);
const Value& operator[](const char* key) const;
Value& operator[](const JSONCPP_STRING& key);
const Value& operator[](const JSONCPP_STRING& key) const;
Value& operator[](const StaticString& key);
// 通过key, 得到value值
Value get(const char* key, const Value& defaultValue) const;
Value get(const JSONCPP_STRING& key, const Value& defaultValue) const;
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
// 得到对象中所有的键值
typedef std::vector<std::string> Members;
Members getMemberNames() const;
将 Value 对象数据序列化为 string
// 序列化得到的字符串有样式 -> 带换行 -> 方便阅读
// 写配置文件的时候
std::string toStyledString() const;
FastWriter 类
// 将数据序列化 -> 单行
// 进行数据的网络传输
std::string Json::FastWriter::write(const Value& root);
Reader 类
bool Json::Reader::parse(const std::string& document,
Value& root, bool collectComments = true);
参数:
- document: json格式字符串
- root: 传出参数, 存储了json字符串中解析出的数据
- collectComments: 是否保存json字符串中的注释信息
// 通过begindoc和enddoc指针定位一个json字符串
// 这个字符串可以是完成的json字符串, 也可以是部分json字符串
bool Json::Reader::parse(const char* beginDoc, const char* endDoc,
Value& root, bool collectComments = true);
// write的文件流 -> ofstream
// read的文件流 -> ifstream
// 假设要解析的json数据在磁盘文件中
// is流对象指向一个磁盘文件, 读操作
bool Json::Reader::parse(std::istream& is, Value& root, bool collectComments = true);
- eg:
#include <json/json.h>
#include <fstream>
#include <iostream>
#include <string>
#include <array>
using namespace Json;
using namespace std;
/*
[
12,
12.34,
true,
"tom",
["jack", "ace", "robin"],
{"sex":"man", "girlfriend":"lucy"}
]
*/
void writeJson()
{
// 将最外层的数组看做一个Value
// 最外层的Value对象创建
Value root;
// Value有一个参数为int 行的构造函数
root.append(12); // 参数进行隐式类型转换
root.append(12.34);
root.append(true);
root.append("tom");
// 创建并初始化一个子数组
Value subArray;
subArray.append("jack");
subArray.append("ace");
subArray.append("robin");
root.append(subArray);
// 创建并初始化子对象
Value subObj;
subObj["sex"] = "woman"; // 添加键值对
subObj["girlfriend"] = "lucy";
root.append(subObj);
// 序列化
#if 0
// 有格式的字符串
// 带换行符
string str = root.toStyledString();
#else
FastWriter f;
// 不带换行符
string str = f.write(root);
#endif
// 将序列化的字符串写磁盘文件
ofstream ofs("test.json");
ofs << str;
ofs.close();
}
void readJson()
{
// 1. 将磁盘文件中的json字符串读到磁盘文件
ifstream ifs("test.json");
// 方法1.不同方法之间需要注释掉前面的方法,否则不可用
// std::string ss((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());
// 方法2
// string buf;
// while (getline(ifs, buf))
// {
// std::cout << buf << std::endl;
// }
// 方法3
// std::array<char, 2048> arr;
// while (ifs.getline(arr.data(), 2048))
// {
// std::cout << arr.data() << std::endl;
// }
// 方法4
// char ch;
// while (ifs.get(ch))
// {
// cout << ch;
// }
// cout << endl;
// 2. 反序列化 -> value对象
Value root;
Reader r;
r.parse(ifs, root);
// r.parse(ss, root);
/*
最新用法:
std::string json=R"(
{
"key":"value"
}
)";
Json::Value root;
Json::CharReaderBuilder jsonReaderBuilder;
std::string jsonReaderError;
std::unique_ptr<Json::CharReader> reader(
jsonReaderBuilder.newCharReader());
reader->parse(json.c_str(),
json.c_str() + json.size(),
&root,
&jsonReaderError);
*/
// 3. 从value对象中将数据依次读出
if (root.isArray())
{
// 数组, 遍历数组
for (int i = 0; i < root.size(); ++i)
{
// 依次取出各个元素, 类型是value类型
Value item = root[i];
// 判断item中存储的数据的类型
if (item.isString())
{
cout << item.asString() << ", ";
}
else if (item.isInt())
{
cout << item.asInt() << ", ";
}
else if (item.isBool())
{
cout << item.asBool() << ", ";
}
else if (item.isDouble())
{
cout << item.asFloat() << ", ";
}
else if (item.isArray())
{
for (int j = 0; j < item.size(); ++j)
{
cout << item[j].asString() << ", ";
}
}
else if (item.isObject())
{
// 对象
// 得到所有的key
Value::Members keys = item.getMemberNames();
for (int k = 0; k < keys.size(); ++k)
{
cout << keys[k] << ":" << item[keys[k]].asString() << ", ";
cout << keys[k] << ":" << item.get(keys[k], "test").asString() << ", ";
}
}
}
cout << endl;
}
ifs.close();
}
int main()
{
writeJson();
readJson();
return 0;
}
- 编译运行
g++ -g test6.cc -ljsoncpp -I /usr/include/jsoncpp/
- eg:
Json::Value root;
Json::Value members;
root["primary_ecu_serial"] = "123";
members["serai_1"] = "info_1";
members["serai_2"] = "info_2";
members["serai_3"] = "info_3";
root["ecu_version_manifests"] = members;
- ref:jsoncpp的下载和编译,Json以及Json在Qt中的使用 【Qt/C/C++】,jsoncpp 的编译和使用