1. 前言
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数据进行交互。
2. C/C++ JSON库比较
基于C/C++实现的JSON库非常多,具体选用那一种JSON解析库主要从解析速度、生成效率、内存占用、接口Api易用性、跨平台集成难度、文档完整性、社区支持力度与可持续性以及自身的应用场景综合考量决定的。下面主要哦才能够解析速度和生成效率两个方面对目前C++领域使用的比较多的JSON进行一个对比。
2.1 解析速度对比
2.2 生成速度对比
2.3 JSON库特点总结
综合上图的两个数据 我们发现RapidJson库表现是相当优异的,在并发数据量非常大的情况下,优势非常明显,但是RapidJson库的缺点也非常明显,就是API接口对于开发者很不友好,接口比较难用。目前在我们公司使用的比较广泛的是Jsoncpp库,这个库的API接口对于调用者非常友好,易于使用与阅读,这是我们选用它的一个非常重要的原因。所以本文主要总结的是Jsoncpp在windows和Linux下的编译方法以及与应用程序集成的方法。
3. Jsoncpp库概述
3.1 Jsoncpp库简介
JsonCpp是一个C ++库,它允许处理JSON值,包括在字符串之间进行序列化和反序列化。它还可以在反序列化/序列化步骤中保留现有注释,从而使其成为存储用户输入文件的便捷格式。 Jsoncpp是基于MIT协议,可以应用于商用项目。
3.2 Jsoncpp源代码地址
https://github.com/open-source-parsers/jsoncpp
3.3 Jsoncpp版本说明
1.y.z
用C ++ 11构建,是最新版本系列。0.y.z
可以与较早的编译器一起使用。00.11.z
可以在新旧编译器中使用。
00.11.z是一个新分支,其主要版本号
00是为了表明它与
0.y.z和不同
1.y.z`,该分支的主要目的是在其他两个分支之间取得平衡。因此,用户可以在1.y.z中引入的这个新分支中使用一些新功能,但是几乎不能应用到0.y.z中。我在写这篇文章时最新的版本是1.9.5,如果没有特殊情况尽量使用最新版的库,1.y.z版本中对于接口有很多优化,尤其是解决了0.y.z版本中不支持long类型数据的问题,Json解析和生成接口相对于老版本也有了很大的提升。
4. Jsoncpp编译与集成方法
4.1 Windows编译集成Jsoncpp
4.1.1 直接源码集成
直接将源代码拷贝到应用程序工程进行使用,不需要编译,但是会让工程不够简洁并且不利于后期版本更新维护,不推荐使用这种方法。
4.1.2 python脚本压缩源码集成
在源代码根目录有一个amalgamate.py脚本,这个脚本是用于压缩源代码用于集成的。这种方式需要在自己电脑安装python 3才能执行python脚本。
执行压缩脚本后在dist目录下生成json.h、json-forwards.h和jsoncpp.cpp三个文件,直接包含在工程中就可以使用了,使用起来很方便。这种方式在跨平台场景上使用起来非常方便,缺点就是每次使用都需要编译。
4.1.3 cmake编译集成
使用Jsoncpp是基于CMakeLists构建的跨平台工程,使用cmake-gui可以生成Visual Studio解决方案,使用Visual Studio编译适合自己的库
4.1.4 vcpkg编译集成
vcpkg对于C++开发者来说绝对是福音,在曾经很长一段时间构建C++开源库就是噩梦,开源库纷繁复杂的构建模式、各种版本库的依赖,真的是痛苦不堪。但是自从github+vcpkg+cmake三角恋产生以后,奇妙的化学反应就发生了,出现了C++包管理器vcpkg。vcpkg需要自己通过源代码进行构建,然后进行配置。使用vcpkg构建Jsoncpp非常简单,源代码都不需要我们下载。
- [vcpkg search jsoncpp]查询Jsoncpp最新的可用版本
- [vcpkg install jsoncpp:x64-windows]构建动态库
- [[vcpkg install jsoncpp:x64-windows-static]构建静态库
4.2 Linux编译集成Jsoncpp
4.2.1 cmake编译集成
对于Linux上利用cmake构建工程需要首先安装cmake工具,通过cmake工具配置参数生成makefile文件,利用make命令进行编译。
cd jsoncpp-1.9.5
mkdir -p build/release
cd build/release
cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=OFF -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -DCMAKE_INSTALL_INCLUDEDIR=include -G "Unix Makefiles" ../..
5.Jsoncpp使用示例
5.1 JSON对象转string对象
Json::Value root;
Json::Value data;
constexpr bool shouldUseOldWay = false;
root["action"] = "run";
data["number"] = 1;
root["data"] = data;
if (shouldUseOldWay)
{
Json::FastWriter writer;
const std::string json_file = writer.write(root);
std::cout << json_file << std::endl;
}
else
{
Json::StreamWriterBuilder builder;
const std::string json_file = Json::writeString(builder, root);
std::cout << json_file << std::endl;
}
5.2 string转JSON对象解析
const std::string rawJson = R"({"Age": 20, "Name": "colin"})";
const auto rawJsonLength = static_cast<int>(rawJson.length());
constexpr bool shouldUseOldWay = false;
JSONCPP_STRING err;
Json::Value root;
if (shouldUseOldWay)
{
Json::Reader reader;
reader.parse(rawJson, root);
}
else
{
Json::CharReaderBuilder builder;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, &err))
{
std::cout << "error" << std::endl;
return EXIT_FAILURE;
}
}
const std::string name = root["Name"].asString();
const int age = root["Age"].asInt();
std::cout << name << std::endl;
std::cout << age << std::endl;
5.3 从文件流载入JSON对象
Json::Value root;
std::ifstream ifs;
ifs.open(argv[1]);
Json::CharReaderBuilder builder;
builder["collectComments"] = true;
JSONCPP_STRING errs;
if (!parseFromStream(builder, ifs, &root, &errs))
{
std::cout << errs << std::endl;
return EXIT_FAILURE;
}
std::cout << root << std::endl;
5.4 JSON对象转流对象
Json::Value root;
Json::StreamWriterBuilder builder;
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
root["Name"] = "robin";
root["Age"] = 20;
writer->write(root, &std::cout);
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
root["Name"] = "robin";
root["Age"] = 20;
writer->write(root, &std::cout);
6.总结
6.总结
JsonCpp在跨平台和使用上非常方便,目前的问题是版本几乎停止没有版本更新。