rapidjson使用简介

本文深入介绍了RapidJSON,一个高性能的C++ JSON解析器及生成器。对比Jsoncpp,RapidJSON在易用性和性能上表现出色,支持多种Unicode编码,提供SAX和DOM风格API。文章通过实例展示了如何使用RapidJSON进行JSON的解析和生成,适用于网络传输和存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

在c++中用来解析Json的库很多,如Jsoncpp

我之前也使用Jsoncpp来做Json解析,但自从接触rapidjson后,特别是尝试使用之后,便决定以后就使用它了,要与Jsoncpp说拜拜。

使用Jsoncpp的同学不妨尝试一下,不管在易用性还是性能方面,rapidjson都是可圈可点的。

RapidJSON 是一个 C++ 的 JSON 解析器及生成器。它的灵感来自 RapidXml。(官网介绍)

  • 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 是只有头文件的 C++ 库。只需把 include/rapidjson 目录复制至系统或项目的 include 目录中。

获取源代码:https://github.com/Tencent/rapidjson

一个简单的读写例程如下。

// rapidjson/example/simpledom/simpledom.cpp`
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <iostream>
using namespace rapidjson;
int main() {
    // 1. 把 JSON 解析至 DOM。
    const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
    Document d;
    d.Parse(json);
    
    // 2. 利用 DOM 作出修改。
    Value& s = d["stars"];
    s.SetInt(s.GetInt() + 1);
    
    // 3. 把 DOM 转换(stringify)成 JSON。
    StringBuffer buffer;
    Writer<StringBuffer> writer(buffer);
    d.Accept(writer);
    
    // Output {"project":"rapidjson","stars":11}
    std::cout << buffer.GetString() << std::endl;
    return 0;
}

其中,json以字符串的形式在程序中给出,包括两个键值对,在c-string中,字符串中的双引号用反斜杠转义。

声明一个DOCUMENT并使用其parse方法把json字符串解析至DOM。利用DOM可取出json中的值,也可以修改其值。

定义一个Writer对象,使用Document的Accept方法写入。最后输出。

前半部分是用来读取Json,后半部分完成写入,非常简单。

解析

RapidJSON 的所有公开类型及函数都在 rapidjson 命名空间中。

这里介绍简单的DOM(Document Object Model, DOM,文件对象模型)。

可以解析一个 JSON 至 DOM,每个 JSON 值都储存为 Value 类,而 Document 类则表示整个 DOM,它存储了一个 DOM 树的根 Value。

待解析的Json格式如下:

{
    "hello": "world",
    "t": true ,
    "f": false,
    "n": null,
    "i": 123,
    "pi": 3.1416,
    "a": [1, 2, 3, 4]
}

解析:

#include "rapidjson/document.h"
using namespace rapidjson;

Document document;
document.Parse(json);

// 省略错误处理和类型检查
printf("hello = %s\n", document["hello"].GetString());
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
printf("i = %d\n", document["i"].GetInt());
printf("pi = %g\n", document["pi"].GetDouble());

// 使用引用来连续访问,方便之余还更高效。
const Value& a = document["a"];
assert(a.IsArray());// 类型检查,异常直接退出
for (SizeType i = 0; i < a.Size(); i++) // 使用 SizeType 而不是 size_t,缺省情况下,SizeType 是 unsigned 的 typedef
        printf("a[%d] = %d\n", i, a[i].GetInt());
        

其他异常检查,如:

assert(document.IsObject());
assert(document.HasMember("hello"));
assert(document["hello"].IsString());

关于数组,Array 与 std::vector 相似,除了使用索引,也可使用迭代器来访问所有元素。

for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
    printf("%d ", itr->GetInt());
    
// 也可以使用c++11的新特性

for (auto& v : a.GetArray())
    printf("%d ", v.GetInt());
生成

Writer 把事件转换成 JSON。它简单易用,如果只是需要把一些数据直接转换为Json,直接使用Writer即可。

如下程序,将生成这样一个Json串:

{"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}

代码:

#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <iostream>
using namespace rapidjson;
using namespace std;

void main() {
    StringBuffer s;
    Writer<StringBuffer> writer(s);
    
    writer.StartObject();
    
    writer.Key("hello");
    writer.String("world");
    writer.Key("t");
    writer.Bool(true);
    writer.Key("f");
    writer.Bool(false);
    writer.Key("n");
    writer.Null();
    writer.Key("i");
    writer.Uint(123);
    writer.Key("pi");
    writer.Double(3.1416);
    
    writer.Key("a");
    writer.StartArray();
    for (unsigned i = 0; i < 4; i++)
        writer.Uint(i);
    writer.EndArray();
    
    writer.EndObject();
    cout << s.GetString() << endl;
}

使用Writer的优点:

  • Writer 必然会输出一个结构良好(well-formed)的 JSON。若然有错误的事件次序(如 Int() 紧随 StartObject() 出现),它会在调试模式中产生断言失败。
  • Writer::String() 可处理字符串转义(如把码点 U+000A 转换成 \n)及进行 Unicode 转码。
  • Writer 一致地处理 number 的输出。
  • Writer 实现了事件处理器 concept。可用于处理来自 Reader、Document 或其他事件发生器。
  • Writer 可对不同平台进行优化。

Writer 所输出的是没有空格字符的最紧凑 JSON,适合网络传输或储存,但不适合人类阅读。

使用PrettyWriter可以得到格式化的Json输出,它在输出中加入缩进及换行。PrettyWriter 的用法与 Writer 几乎一样,不同之处是 PrettyWriter 提供了一个 SetIndent(Ch indentChar, unsigned indentCharCount) 函数。缺省的缩进是 4 个空格。

总结

个人感觉是rapidjson提供了比Jsoncpp灵活得多的类型,使得编码及解码时更自由随意,不必为了找不到的类型而纠结。

另外,根据资料,rapidjson的性能是Jsoncpp的好多倍,经过实测,确实性能表现较好。

当然,rapidjson的header-only特性也是大大的加分项,不必安装库,移植、部署都很方便。

更多内容在实践继续探索。

参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值