【C/C++】C++Json解析和生成的开源库:RapidJson和JsonCpp

目录

一,RapidJson和JsonCpp对比

二,RapidJson和JsonCpp下载地址

1.RapidJson下载

2.JsonCpp下载

三,RapidJson头文件及其功能介绍

1.rapidjson/document.h

2.rapidjson/writer.h

3.rapidjson/stringbuffer.h

4.rapidjson/reader.h

5.rapidjson/error/en.h

6.rapidjson/error/error.h

四,RapidJson使用案例

1.安装RapidJson

2.测试的Json数据

3.使用DOM解析器解析JSON

4.使用DOM解析器生成JSON

五,JsonCpp使用

六,其它


一,RapidJson和JsonCpp对比

RapidJson和JsonCpp都是C++中流行的JSON解析器和生成器,并且都是开源库,具有许多相似的功能,但也有不同之处。

1.RapidJson优势

  • RapidJSON的速度比JsonCpp更快,因为它使用了更高效的内存管理和解析算法。
  • RapidJSON在内存使用方面比JsonCpp更加高效,因为它使用了基于堆栈的内存池。
  • RapidJSON提供了很多灵活的解析和生成JSON的选项,例如支持按需解析和生成,可以通过模板自定义数据类型的序列化和反序列化等等。
  • RapidJSON代码体积非常小,只有几个头文件和源文件,没有外部依赖,而且只依赖于标准C++库,因此很容易部署到现有项目中,非常轻量级。

2.JsonCpp优势

  • JsonCpp是一个稳定且经过长期使用和测试的库,具有更广泛的社区支持和使用。
  • JsonCpp提供了更加简单的API,易于学习和使用,它的代码结构也很清晰,方便阅读和理解。
  • JsonCpp提供了更多的功能,例如支持JSON格式化,可以在解析时检查语法错误等等。
  • JsonCpp可移植性好,可以在多种操作系统和编译器上运行,包括Windows、Linux和Mac OS X。

3.两者的差异

  • RapidJSON的设计理念更加注重性能,而JsonCpp的设计理念更加注重易用性。
  • RapidJSON提供了更多的可扩展性选项,而JsonCpp则更加易于移植。

4.根据具体需求进行选择

  • 如果你需要一个快速和高效处理大量JSON数据的库,并且愿意使用更灵活的解析和生成选项,那么RapidJSON是一个很好的选择。
  • 如果你需要一个更稳定,易于使用和可移植的库,并且需要额外的功能(例如JSON格式化),那么JsonCpp是一个不错的选择。

二,RapidJson和JsonCpp下载地址

1.RapidJson下载

  1. 开源库地址:https://github.com/Tencent/rapidjson
  2. 开发文档:http://rapidjson.org/zh-cn/ 

2.JsonCpp下载

  1. 开源库地址:https://github.com/open-source-parsers/jsoncpp

三,RapidJson头文件及其功能介绍

1.rapidjson/document.h

该头文件包含了DOM解析器和生成器所需的类和函数。DOM解析器是一种将JSON文本解析为DOM树的解析器,DOM树的结构对应于JSON文本的语法结构。DOM生成器是一种将DOM树转换为JSON文本的生成器。该头文件中的类包括:

  • GenericValue: 一个通用的JSON值类型,可以表示任何类型的JSON值,包括null、bool、int、double、字符串、数组和对象。
  • Document: 表示一个JSON文档,包含一个根节点和相关的配置选项。

2.rapidjson/writer.h

该头文件包含了生成器所需的类和函数,用于将DOM树转换为JSON文本。该头文件中的类包括:

  • Writer: 将DOM树转换为JSON文本的基类。
  • PrettyWriter: 继承自Writer,支持格式化输出的生成器,生成的JSON文本带有缩进和换行符。
  • WriterTraits: 定义了生成器的一些常见特性,如逗号的位置、缩进符号等。

3.rapidjson/stringbuffer.h

该头文件包含了一个字符串缓冲区类,用于存储生成器生成的JSON文本。该头文件中的类包括:

  • StringBuffer: 表示一个字符串缓冲区,提供了向缓冲区写入数据的方法。
  • CrtAllocator: 表示一个内存分配器,用于分配和释放内存。

4.rapidjson/reader.h

该头文件包含了SAX解析器所需的类和函数,用于将JSON文本解析为SAX事件流。SAX解析器是一种将JSON文本解析为SAX事件流的解析器,SAX事件流表示JSON文本的语法结构。该头文件中的类包括:

  • BaseReaderHandler: 解析器事件处理程序的基类。
  • Reader: 将JSON文本解析为SAX事件流的解析器。

5.rapidjson/error/en.h

该头文件包含了RapidJSON的错误码和错误信息的定义。该头文件中的类包括:

  • ParseErrorCode: 定义了解析器可能出现的错误码。
  • GetParseErrorFunc: 用于获取错误码对应的错误信息。

6.rapidjson/error/error.h

该头文件包含了解析器和生成器可能出现的错误异常类的定义。该头文件中的类包括:

  • ParseException: 解析器可能抛出的异常类。
  • RuntimeError: 生成器可能抛出的异常类。

四,RapidJson使用案例

1.安装RapidJson

1.RapidJSON 是只有头文件的 C++ 库,没有安装过程。下载解压后只需把 include/rapidjson 目录拷贝到你的项目中即可开始使用(支持SAX和DOM两种解析方式:SAX解析器将JSON流解析为事件序列,而DOM解析器将JSON解析为内存中的树形结构)

VS2019工程

VsCode工程(参考)

2.测试的Json数据

准备测试读写的 example.json 文件内容(文件路径 E:\example.json)

  {
      "FirstName": "Fu",
      "LastName": "Cong",
      "Age": 24,
      "Address": {
          "Street": "首创悦榕汇",
          "City": "BeiJing",
          "Country": "BeiJing"
      },
      "Phone numbers": [
          "+44 12345",
          678910
      ]
  }

3.使用DOM解析器解析JSON

#include <iostream>
#include <fstream>
#include "rapidjson/document.h"
//返回指定文件的所有内容
char* readFile(std::string path)
{
    std::ifstream ifs;
    ifs.open(path, ios::in);
    char* data = NULL;
    long length;    //文件大小
    if (ifs.is_open()) {
        //文件打开成功
        ifs.seekg(0, ios::end);  //将文件流光标移动到文件末尾
        length = ifs.tellg();   //获取文件内容的大小(相对于文件开头的位移量来表示)
        data = (char*)malloc((length + 1) * sizeof(char));
        memset(data, '\0', length);
        ifs.seekg(0, ios::beg);  //将文件光标重置到文件开头位置
        ifs.read(data, length);  //一次性读取所有字符串
        ifs.close();    //关闭文件流
        return data;
    }
    return NULL;
}
void readJson()
{
    std::string jsonData(readFile("E:\\example.json"));

    rapidjson::Document doc;    //Document是一个表示根DOM的JSON值。根可以是对象或数组。
    if(doc.Parse(jsonData.c_str()).HasParseError()){
        std::cout << "“正常”解析,解码字符串到新的缓冲区失败!" << std::endl;
        return;
    }else{
        std::cout << "解析文档成功!" << std::endl;
    }
    
     if (doc.IsObject()) {
        //JSON根数据是对象
        if (doc.HasMember("FirstName") && doc["FirstName"].IsString()) {
            std::cout << "FirstName:" << doc["FirstName"].GetString() << std::endl;
        }
        if(doc.HasMember("LastName") && doc["LastName"].IsString()){
            std::cout << "LastName:" << doc["LastName"].GetString() << std::endl;
        }
        if(doc.HasMember("Age") && doc["Age"].IsInt()){
            std::cout << "Age:" << doc["Age"].GetInt() << std::endl;
        }
        if(doc.HasMember("Address") && doc["Address"].IsObject()){
            rapidjson::Value &subObj = doc["Address"].GetObject();
            if(subObj.HasMember("Street") && subObj["Street"].IsString()){
                std::cout << "Street:" << subObj["Street"].GetString() << std::endl;
            }
            if(subObj.HasMember("City") && subObj["City"].IsString()){
                std::cout << "City:" << subObj["City"].GetString() << std::endl;
            }
            //从0.2版本开始,可以使用单一查找来检查成员的存在及其值(个人觉得并不好用)
            rapidjson::Value::MemberIterator street = subObj.FindMember("Country");
            if(street != doc.MemberEnd() && street->value.IsString()){
                std::cout << "Country:" << street->value.GetString() << std::endl;
            }
        }
        if(doc.HasMember("Phone numbers") && doc["Phone numbers"].IsArray()){
            const rapidjson::Value& arr = doc["Phone numbers"];
            for(rapidjson::SizeType i = 0; i< arr.Size();i++){
                if (arr[i].IsString()) {
                    std::cout << arr[i].GetString() << std::endl;
                }
                if (arr[i].IsInt()) {
                    std::cout << arr[i].GetInt() << std::endl;
                }
            }
        }
    }else if(doc.IsArray()){
        //JSON根数据是数组
    }
}

4.使用DOM解析器生成JSON

#include <iostream>
#include <fstream>
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"    //存储生成的JSON文本,然后可以轻松地将其输出到文件或其他输出流中
#include "rapidjson/prettywriter.h"    //生成带有格式的JSON文本,并将其输出到文件中
void writeJson()
{
    rapidjson::Document docRoot;
    docRoot.SetObject();    //创建一个JSON对象

    //加入键值对
    docRoot.AddMember("FirstName","Fu",docRoot.GetAllocator());
    docRoot.AddMember("LastName","Cong",docRoot.GetAllocator());
    docRoot.AddMember("Age",24,docRoot.GetAllocator());

    //添加子对象
    rapidjson::Value subObj(rapidjson::kObjectType);
    subObj.AddMember("Street","首创悦榕汇",docRoot.GetAllocator());
    subObj.AddMember("City","BeiJing",docRoot.GetAllocator());
    subObj.AddMember("Country","BeiJing",docRoot.GetAllocator());
    docRoot.AddMember("Age",subObj,docRoot.GetAllocator());

    //添加数组
    rapidjson::Value PhoneNumber(rapidjson::kArrayType);
    rapidjson::Value val1;
    val1.SetString("+44 12345", docRoot.GetAllocator());
    PhoneNumber.PushBack(val1,docRoot.GetAllocator());
    rapidjson::Value val2;
    val2.SetInt(678910);
    PhoneNumber.PushBack(val2,docRoot.GetAllocator());
    docRoot.AddMember("Phone numbers",PhoneNumber,docRoot.GetAllocator());

    //输出到Json文件中
    rapidjson::StringBuffer buffer;     //创建一个StringBuffer对象
    // rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);  //创建一个Writer对象并将其与StringBuffer对象连接起来,生成不带有格式的JSON文本
    rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);    //创建一个PrettyWriter对象并将其与StringBuffer对象连接起来,生成带有格式的JSON文本
    docRoot.Accept(writer);     //将JSON对象写入StringBuffer对象
    std::string json_str = buffer.GetString();      //将StringBuffer对象转换为std::string
    
    std::ofstream ofs;
    ofs.open("E:\\example.json",std::ios::out);
    if(ofs.is_open()){
        ofs << json_str;
        ofs.close();
    }
}

五,JsonCpp使用

参考这篇文章: JsonCpp编译和使用 | 爱编程的大丙

六,其它

cJSON的使用 :cJSON的API介绍和使用

猜你喜欢

转载自blog.csdn.net/weixin_43729127/article/details/129473932