C++json库nlohmannjson使用介绍

文章介绍了C++库nlohmann/json的主要优点,如直观语法、高代码质量、内存效率和速度。通过示例展示了如何创建Json对象、进行序列化和反序列化操作,并提出了在遇到问题如缺少字段、特殊字符和类型不匹配时的解决办法。
摘要由CSDN通过智能技术生成

1、简介

最近项目中需要使用C++ Json序列化和反序列化,顺便调研了下目前比较好用的C++ json库,发现nlohmann/json应该是其中相对较好的json库。nlohmann/json有如下主要优点:

1、语法比较直观,类似于Python。

2、要使用nlohmann/json,只需要引入头文件json.hpp。无需引入lib之类的。

#include <nlohmann/json.hpp>

// for convenience
using json = nlohmann::json;

3、经过非常多的测试,代码质量非常高,没有内存泄漏。

4、内存效率、速度相对其它库较高。

2、实例介绍

2.1 创建Json对象

使用nlohmann/json创建Json对象,无需关心值类型,比如创建如下Json对象:

// create an empty structure (null)
json j;

// add a number that is stored as double (note the implicit conversion of j to an object)
j["pi"] = 3.141;

// add a Boolean that is stored as bool
j["happy"] = true;

// add a string that is stored as std::string
j["name"] = "Niels";

// add another null object by passing nullptr
j["nothing"] = nullptr;

// add an object inside the object
j["answer"]["everything"] = 42;

// add an array that is stored as std::vector (using an initializer list)
j["list"] = { 1, 0, 2 };

// add another object (using an initializer list of pairs)
j["object"] = { {"currency", "USD"}, {"value", 42.99} };

// instead, you could also write (which looks very similar to the JSON above)
json j2 = {
  {"pi", 3.141},
  {"happy", true},
  {"name", "Niels"},
  {"nothing", nullptr},
  {"answer", {
    {"everything", 42}
  }},
  {"list", {1, 0, 2}},
  {"object", {
    {"currency", "USD"},
    {"value", 42.99}
  }}
};
2.2 序列/反序列化

在class/struct内部定义NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, …)

class Address
{
	std::string street;
	int housenumber;
	int postcode;
public:
	NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, street, housenumber, postcode)
};
字符串转成class/struct
std::string strTemp =(R"({"street": "test", "housenumber": 0, "postcode": 0})";
Address temp = nlohmann::json::parse(strTemp).get<Address>();
class/struct转成字符串
Addree temp{"Test", 0, 0};
nlohmann::json jsonTemp = temp;
std::string strTemp = jsonTemp.dump();

为了方便序列/反序列化,可以封装下面两个接口:

template<class T>
   static void deserialize(const std::string &str, T &value)
   {
       if (str.size() <= 0)
           return;
       value = parse(str).template get<T>();
   }
template<class T>
    static void serialize(const T &value, std::string &str)
    {
        str = json(value).dump();
    }

3、遇到的问题及解决办法

3.1 strings参数比class/struct的参数少,反序列化崩溃

实际项目中,json使用未必非常标准,有解析strings参数比较少的需求。比如2.2中类Address

std::string strTemp =(R"({"street": "test", "housenumber": 0})";
Address temp = nlohmann::json::parse(strTemp).get<Address>();

strTemp少了postcode,执行第二行代码就会崩溃。

解决办法

打开nlohmann/json.hpp找到源码

#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); 

将其改成

#define NLOHMANN_JSON_FROM(v1) if(nlohmann_json_j.contains(#v1)){nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);}

相比源码,就加了contains的判断,若待解析的json没有对应字段,就不作处理。

3.2 strings包含中文、“\"等反序列化崩溃

strings包含中文、“\“等“特殊字符”,用nlohmann::json反序列化就会崩溃。跟大多数json库一样,nlohmann::json是不支持中文、”\"等“特殊字符”的,因此需要先替换strings中的特殊字符,再反序列化。

3.3 类型必须匹配,数字无法转成string

实际项目中协议定的某些字段,经常出现数字、string混用的情况。nlohmann/json默认实现要求反序列化的目标class/struct参数类型和strings中完美匹配,否则解析过程中崩溃。

解决办法

原代码

template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
    {
         JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); 
    }
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}

改造后

template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
    {
        /* 为了提高健壮性,对于json中非string的类型,也将其转成string */
        s = to_string(j);
        return;
        /* JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); */
    }
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
3.4 NLOHMANN_DEFINE_TYPE_INTRUSIVE不支持class/struct参数过多(超过63个)

NLOHMANN_DEFINE_TYPE_INTRUSIVE并不能无限展开,nlohmann/json默认支持63个参数。

解决方案

NLOHMANN_DEFINE_TYPE_INTRUSIVE的定义如下:

#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \
    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }

NLOHMANN_DEFINE_TYPE_INTRUSIVE的原理就是用NLOHMANN_JSON_EXPAND,1个NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, …))可以支持63个,超过可以另起1个,如下:

struct StructTest
{
	std::string param1;
	std::string param2;
	...
	std::string param63;
	std::string param64;
	...

    friend void from_json(const nlohmann::json& nlohmann_json_j, StructTest& nlohmann_json_t)
    {
        NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param1, param2, ..., param63));
		NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param64, param65, ...));
    }
    friend void to_json(nlohmann::json& nlohmann_json_j, const StructTest& nlohmann_json_t)
    {
        NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param1, param2, ..., param63));
		NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(func, param64, param65, ...));
    }
};
  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在C++使用JSON,你可以选择安装一些流行的开源,如jsoncpp、rapidjsonnlohmann/json。下面是安装这些的一些基本步骤: 1. jsoncpp:这是一个跨平台的C++ JSON。你可以从它的GitHub仓(https://github.com/open-source-parsers/jsoncpp)下载源代码。 - 使用以下命令克隆jsoncpp的源代码到本地目录中: ``` git clone https://github.com/open-source-parsers/jsoncpp.git ``` - 进入jsoncpp目录: ``` cd jsoncpp ``` - 创建一个build目录,并进入该目录: ``` mkdir build cd build ``` - 使用CMake生成项目文件: ``` cmake .. ``` - 编译并安装: ``` make sudo make install ``` - 安装完成后,你可以在你的C++项目中使用jsoncpp了。 2. rapidjson:这是一个快速的C++ JSON解析生成器。你可以从它的GitHub仓(https://github.com/Tencent/rapidjson)下载源代码。 - 使用以下命令克隆rapidjson的源代码到本地目录中: ``` git clone https://github.com/Tencent/rapidjson.git ``` - 将rapidjson目录中的`include/rapidjson`目录复制到你的项目中。 - 在你的C++项目中包含rapidjson的头文件即可开始使用。 3. nlohmann/json:这是一个现代化的C++ JSON,可以使用简单的API进行操作。你可以从它的GitHub仓(https://github.com/nlohmann/json)下载源代码。 - 使用以下命令克隆nlohmann/json的源代码到本地目录中: ``` git clone https://github.com/nlohmann/json.git ``` - 将nlohmann/json目录中的`single_include/nlohmann`目录复制到你的项目中。 - 在你的C++项目中包含nlohmann/json的头文件即可开始使用。 这些是一些常用的C++ JSON,你可以根据自己的需求选择合适的使用。安装完成后,你就可以使用这些来解析和生成JSON数据了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值