json简介
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
JSON建构于两种结构:
“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
JSON具有以下这些形式:
对象是一个无序的“‘名称/值’对”集合。一个对象以 {左括号 开始, }右括号 结束。每个“名称”后跟一个 :冒号 ;“‘名称/值’ 对”之间使用 ,逗号 分隔。
想要详细了解可点击json官网查看
jsoncpp和rapidjson对比
jsoncpp和rapidjson是两款常用C++11编写的第三方开源JSON序列化与反序列化库, 两者都基于MIT协议发布,对商用较友好,以下从使用上和性能上对两者做出评价,方便不同应用场景选择。
rapidjson
纯头文件: rapidjson只包含头文件,不包含源文件,非常方便集成到项目中;中间对象JSON value: 构造较复杂, 涉及到内存分配器;自包含:rapidjson完全是一个独立的项目,不依赖与第三个库,比如不依赖BOOST,甚至可以不依赖STL;速度快:性能类似于strlen()。 jsoncpp
头文件源文件并存: 一般根据平台编译成动态库引入项目; 中间对象JSON value:构造较容易,使用较方便。在使用上jsoncpp更胜一筹,性能上rapidjson更好
rapidjson使用
rapidjson简介
rapidjson官网
RapidJSON是腾讯开源的一个高效的C++ JSON解析器及生成器,它是只有头文件的C++库。RapidJSON 是一个 C++ 的 JSON 解析器及生成器。
RapidJSON 小而全。它同时支持 SAX 和 DOM 风格的 API。SAX 解析器只有约 500 行代码。RapidJSON 快。它的性能可与 strlen() 相比。可支持 SSE2/SSE4.2 加速。RapidJSON 独立。它不依赖于 BOOST 等外部库。它甚至不依赖于 STL。RapidJSON 对内存友好。在大部分 32/64 位机器上,每个 JSON 值只占 16 字节(除字符串外)。它预设使用一个快速的内存分配器,令分析器可以紧凑地分配内存。RapidJSON 对 Unicode 友好。它支持 UTF-8、UTF-16、UTF-32 (大端序/小端序),并内部支持这些编码的检测、校验及转码。例如,RapidJSON 可以在分析一个 UTF-8 文件至 DOM 时,把当中的 JSON 字符串转码至 UTF-16。它也支持代理对(surrogate pair)及 "\u0000"(空字符)。
rapidjson下载及使用
RapidJSON GitHubRapidJSON网盘链接 提取码:2mjk
RapidJSON 是只有头文件的 C++ 库。只需把 include/rapidjson 目录复制至系统或项目的 include 目录中即可。
Document d;
// 使用 Set() 创建 DOM
Pointer("/project").Set(d, "RapidJSON");
Pointer("/stars").Set(d, 10);
// { "project" : "RapidJSON", "stars" : 10 }
// 使用 Get() 访问 DOM。若该值不存在则返回 nullptr。
if (Value* stars = Pointer("/stars").Get(d))
stars->SetInt(stars->GetInt() + 1);
// { "project" : "RapidJSON", "stars" : 11 }
// Set() 和 Create() 自动生成父值(如果它们不存在)。
Pointer("/a/b/0").Create(d);
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } }
// GetWithDefault() 返回引用。若该值不存在则会深拷贝缺省值。
Value& hello = Pointer("/hello").GetWithDefault(d, "world");
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "world" }
// Swap() 和 Set() 相似
Value x("C++");
Pointer("/hello").Swap(d, x);
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
// x 变成 "world"
// 删去一个成员或元素,若值存在返回 true
bool success = Pointer("/a").Erase(d);
assert(success);
// { "project" : "RapidJSON", "stars" : 10 }
rapidjson简单示例
使用前的准备工作
包含头文件
#include "iostream" //输入输出
#include "rapidjson/filereadstream.h" //文件输入流
#include "rapidjson/filewritestream.h" //文件输出流
#include "rapidjson/prettywriter.h" //文件格式化输出
#include "rapidjson/pointer.h"
#include "rapidjson/document.h"
将上述rapidjson文件引入工程使用的json文件格式
{
"msg": "json",
"person1": [
"zhangsan",
30,
"英语"
],
"person2": {
"language": "汉语",
"name": "lisi",
"salary": 100
},
"person3": [
{
"language": "日语",
"name": "wangwu",
"salary": 24
},
{
"language": "法语",
"name": "zhaoliu",
"salary": 209
}
],
"person4": [
"zhouqi",
109,
"英语"
]
}
写文件
bool ByRapidJson::WriteJsonData(std::string &FileName)
{
rapidjson::Document d;
//赋值
rapidjson::Pointer("/msg").Set(d, "json");
rapidjson::Pointer("/person1/0").Set(d, "zhangsan");
rapidjson::Pointer("/person1/1").Set(d, 30);
rapidjson::Pointer("/person1/2").Set(d, "英语");
rapidjson::Pointer("/person2/language").Set(d, "汉语");
rapidjson::Pointer("/person2/name").Set(d, "lisi");
rapidjson::Pointer("/person2/salary").Set(d, 100);
rapidjson::Pointer("/person3/0/language").Set(d, "日语");
rapidjson::Pointer("/person3/0/name").Set(d, "wangwu");
rapidjson::Pointer("/person3/0/salary").Set(d, 24);
rapidjson::Pointer("/person3/1/language").Set(d, "法语");
rapidjson::Pointer("/person3/1/name").Set(d, "zhaoliu");
rapidjson::Pointer("/person3/1/salary").Set(d, 209);
rapidjson::Pointer("/person4/0").Set(d, "zhouqi");
rapidjson::Pointer("/person4/1").Set(d, 109);
rapidjson::Pointer("/person4/2").Set(d, "英语");
//写入文件
char Buffer[65536];
FILE* wfp = fopen(FileName.c_str(), "wb");
rapidjson::FileWriteStream os(wfp, Buffer, sizeof(Buffer));
//格式化输出
rapidjson::PrettyWriter writer(os);
//无格式输出
//rapidjson::Writer writer(os);
d.Accept(writer);
fclose(wfp);
return true;
}
读文件
bool ByRapidJson::ReadJsonData(std::string &FileName)
{
FILE* rfp = fopen(FileName.c_str(), "rb"); // 非 Windows 平台使用 "r"
char readBuffer[65536];
rapidjson::FileReadStream is(rfp, readBuffer, sizeof(readBuffer));
fclose(rfp);
rapidjson::Document document;
document.ParseStream(is);
//节点三包含其他内容,因此示例只解析节点三
//若不存在则返回空
if (rapidjson::Value* per3_language = rapidjson::Pointer("/person3/0/language").Get(document))
std::cout << "language:" << per3_language->GetString() << std::endl;
if (rapidjson::Value* per3_language = rapidjson::Pointer("/person3/0/name").Get(document))
std::cout << "name:" << per3_language->GetString() << std::endl;
if (rapidjson::Value* per3_language = rapidjson::Pointer("/person3/0/salary").Get(document))
std::cout << "salary:" << per3_language->GetInt() << std::endl;
std::cout << std::endl;
//需要进行安全处理
std::cout << "language:" << GetValueByPointer(document, "/person3/1/language")->GetString() << std::endl;
std::cout << "name:" << GetValueByPointer(document, "/person3/1/name")->GetString() << std::endl;
std::cout << "salary:" << GetValueByPointer(document, "/person3/1/salary")->GetInt() << std::endl;
return true;
}
更新文件
bool ByRapidJson::UpdateJsonData(std::string &FileName)
{
//读取
FILE* rfp = fopen(FileName.c_str(), "rb"); // 非 Windows 平台使用 "r"
char Buffer[65536];
rapidjson::FileReadStream is(rfp, Buffer, sizeof(Buffer));
fclose(rfp);
rapidjson::Document document;
document.ParseStream(is);
//节点1加10分
if (rapidjson::Value* person1_sa = rapidjson::Pointer("/person1/1").Get(document))
{
person1_sa->SetInt(person1_sa->GetInt() + 10);
}
//节点2换成C++
if (rapidjson::Value* person1_sa = rapidjson::Pointer("/person2/language").Get(document))
{
rapidjson::Value x("C++");
rapidjson::Pointer("/person2/language").Swap(document, x);
std::cout << "swap值为:" << x.GetString() << std::endl;
}
//删除msg节点
bool success = rapidjson::Pointer("/msg").Erase(document);
if (success)
{
std::cout << "删除成功" << std::endl;
}
else
{
std::cout << "删除失败,节点不存在" << std::endl;
}
//增加MSG节点
rapidjson::Pointer("/MSG").Set(document, "json");
//写入文件
FILE* wfp = fopen(FileName.c_str(), "wb");
rapidjson::FileWriteStream os(wfp, Buffer, sizeof(Buffer));
//格式化输出
rapidjson::PrettyWriter writer(os);
//无格式输出
//rapidjson::Writer writer(os);
document.Accept(writer);
fclose(wfp);
return true;
}
注:转移语义
在设计 RapidJSON 时有一个非常特别的决定,就是 Value 赋值并不是把来源 Value 复制至目的 Value,而是把来源 Value 转移(move)至目的 Value。例如
Value a(123);
Value b(456);
b = a; // a 变成 Null,b 变成数字 123。
为什么?此语义有何优点?
最简单的答案就是性能。对于固定大小的 JSON 类型(Number、True、False、Null),复制它们是简单快捷。然而,对于可变大小的 JSON 类型(String、Array、Object),复制它们会产生大量开销,而且这些开销常常不被察觉。尤其是当我们需要创建临时 Object,把它复制至另一变量,然后再析构它。
测试代码
rapidjson::Value a("a1");
rapidjson::Value b("b1");
std::cout << a.GetString() << " " << b.GetString() << std::endl;
a = b;
std::cout << a.GetString() << " ";// << b.GetString() << std::endl;
if (b.IsNull())
{
std::cout << " b is null";
}
jsoncpp使用
jsoncpp简介
jsoncpp是c++解析JSON串常用的解析库之一,它是一个序列化反序列JSON格式的开源C++库,被C++程序广泛使用(包括Chromium项目)。JsonCpp还有一个重要特性是其支持在JSON格式内注释,这对于使用JSON格式作为配置文件很有意义,可以给配置添加注释说明其用途。
jsoncpp下载及使用
jsoncpp的Github下载地址:jsoncpp
也可直接下载网盘内容,已生成好了
百度网盘链接:提取码:zh4l
下载完源码之后为了使用方便,直接将源码嵌入到工程中,进入源码所在目录,先生成一个完整的头文件和cpp文件,命令如下(需要python环境):
python amalgamate.py
然后将dist文件夹更名为jsoncpp拷贝到工程目录就可以使用了。(包含json/json.h、json/json-forwards.h、json.cpp)
json简单示例
使用前的准备工作
包含头文件
#include //读写io c++标准库
#include //读写文件 c++标准库
#include //字符串类 c++标准库
#include //字符串流 c++标准库
#include "jsoncpp/json/json.h" //jsoncpp的头文件
将上述jsoncpp文件加入工程使用的json文件格式
{
"msg" : "json",
"person1" : [ "zhangsan", 30, "英语" ],
"person2" : {
"language" : "汉语",
"name" : "lisi",
"salary" : 100
},
"person3" : [
{
"language" : "日语",
"name" : "wangwu",
"salary" : 24
},
{
"language" : "法语",
"name" : "zhaoliu",
"salary" : 209
}
],
"person4" : [ "zhouqi", 109, "英语" ]
}
写文件
bool ByJsoncpp::WriteJsonData(std::string &JsonFileName)
{
Json::Value root;
// 组装json内容
root["msg"] = "json";
{
Json::Value person;
person[0] = "zhangsan";
person[1] = 30;
person[2] = "英语";
root["person1"] = person;
}
{
Json::Value person;
person["name"] = "lisi";
person["salary"] = 100;
person["language"] = "汉语";
root["person2"] = person;
}
{
Json::Value person;
Json::Value person1;
person1["name"] = "wangwu";
person1["salary"] = 24;
person1["language"] = "日语";
Json::Value person2;
person2["name"] = "zhaoliu";
person2["salary"] = 209;
person2["language"] = "法语";
person[0] = person1;
person[1] = person2;
root["person3"] = person;
}
{
Json::Value person;
person[0] = "zhouqi";
person[1] = 109;
person[2] = "英语";
root["person4"] = person;
}
//无格式输出到文件
//Json::FastWriter writer;
// 将json内容(缩进格式)输出到文件
Json::StyledWriter writer;
std::ofstream os;
os.open(JsonFileName.c_str());
if (!os.is_open())
{
std::cout << "open json file failed." << std::endl;
return false;
}
os << writer.write(root);
os.close();
return true;
}
读文件
bool ByJsoncpp::ReadJsonData(std::string &JsonFileName)
{
// 以二进制形式读取json文件内容
std::ifstream is(JsonFileName.c_str(), std::ios::binary);
if (!is.is_open())
{
std::cout << "open json file failed." << std::endl;
return false;
}
Json::Reader reader;
Json::Value root;
// 解析json内容
if (reader.parse(is, root))
{
//节点三包含其他内容,因此示例只解析节点三
Json::Value root3 = root["person3"];
int num = root3.size();
for (int i = 0; i < root3.size(); i++)
{
std::cout << "language:" << root3[i]["language"].asString() << std::endl;
std::cout << "name:" << root3[i]["name"].asString() << std::endl;
std::cout << "salary:" << root3[i]["salary"].asInt() << std::endl;
std::cout << std::endl;
}
//键不存在时,值为空
std::cout << "test is: " << root["test"].asString() << std::endl;
}
is.close();
return true;
}
中文乱码问题处理
当我们使用jsoncpp读取写入json文件时,会发现明明是中文字符串,但是赋值给Json::Value后却变成\u这样的了,而且读取出来还是乱码的。
原因是jsoncpp.cpp中的中文被转码了,将如下
找到jsoncpp.cpp里面的valueToQuotedStringN函数,找到最后switch的default;如下图将原来的代码注释掉,换成新的那一行代码;