1 nlohmann json开发环境配置

nlohmann json是一个C++、开源的,只有单个头文件的、高效快速的json操作库。

优点:

  • 现代C++风格,语法直观,使用简单
  • 没有复杂的编译、依赖关系,直接包含头文件即可

缺点:

  • 并不是最快的json库
  • 内存占用稍大

Github仓库:https://github.com/nlohmann/json

因为nlohmann json支持单个头文件,所以在配置其开发环境时只需要下载其发布包include.zip,解压缩该压缩包,然后将该文件下的子文件夹single_include添加到项目中头文件路径即可。

使用时,在代码中包含其头文件

#include "nlohmann/json.hpp"

即可使用,非常简单。

2 nlohmann json的使用

2.1 json解析

2.1.1 json解析中的异常和容错处理

2.1.1.1 判断字符串是否可以被解析为json对象

在将字符串解析成json对象时,需要判断该字符串是可以被解析成json对象,我们可以使用以下代码

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    const std::string json_str = "niubi";

    // 判断是否可以解析为json对象
    if (!nlohmann::json::accept(json_str))
    {
        std::cerr << "parse json failed" << std::endl;
    }

    return 0;
}

也可以使用try...catch捕捉解析异常,通过捕捉异常判断是否可以正常解析为json对象,如以下代码

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    const std::string json_str = "niubi";

    try
    {
        nlohmann::json root = nlohmann::json::parse(json_str);
    }
    catch (nlohmann::json::parse_error& e)
    {
        std::cerr << "parse json failed, error message:"<< e.what() << std::endl;
    }

    return 0;
}

如果不想让nlohmann::json::parse抛出异常,则可将

nlohmann::json root = nlohmann::json::parse(json_str);

修改为

nlohmann::json root = nlohmann::json::parse(json_str,nullptr,false);

这样就不会抛出异常了。

2.1.1.2 判断json对象是否包含键值

在解析json对象时,为了避免某个键值为空导致后续操作失败的问题,通常需要判断json是否包含某个键值,示例代码如下

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    const std::string json_str = "{\"data\":0}";

    try
    {
        nlohmann::json root = nlohmann::json::parse(json_str,nullptr,false);
        if (root.contains("data"))
        {
            int data_value = root["data"].get<int>();

            std::cout << "parse success, the value data:" << data_value << std::endl;
        }
        else
        {
            std::cerr << "json not contains data key" << std::endl;
        }
    }
    catch (nlohmann::json::parse_error& e)
    {
        std::cerr << "parse json failed, error message:"<< e.what() << std::endl;
    }

    return 0;
}
2.1.1.3 判断json对象键值对应值的数据类型

其实上一小节中的代码是有问题的,我直接使用

int data_value = root["data"].get<int>();

去获取data对应的int类型的值,如果data对应的不是int类型的话会出现错误,在不出现错误的情况下,解析出来的值也会不正确,所以应该先对data对应的值的数据类型进行判断,增强程序的健壮性,修改后的代码如下

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    const std::string json_str = "{\"data\":0}";

    try
    {
        nlohmann::json root = nlohmann::json::parse(json_str,nullptr,false);
        if (root.contains("data"))
        {
            if (root["data"].is_number_integer())
            {
                int data_value = root["data"].get<int>();

                std::cout << "parse success, the value data:" << data_value << std::endl;
            }
            else
            {
                std::cerr << "key value is not int type" << std::endl;
            }
        }
        else
        {
            std::cerr << "json not contains data key" << std::endl;
        }
    }
    catch (nlohmann::json::parse_error& e)
    {
        std::cerr << "parse json failed, error message:"<< e.what() << std::endl;
    }

    return 0;
}

2.1.2 从文本文件中解析json

nlohmann json支持直接从文件对象中解析json,示例代码如下

#include <iostream>
#include <fstream>
#include "nlohmann/json.hpp"

int main()
{
    const std::string file_path = "example.json";

    std::ifstream file(file_path);

    try
    {
        nlohmann::json root = nlohmann::json::parse(file);
    }
    catch (nlohmann::json::parse_error& e)
    {
        std::cerr << "parse json failed, error message:" << e.what() << std::endl;
    }

    return 0;
}

2.1.3 从字符串中解析json

nlohmann json支持直接从字符串中解析json,示例代码如下

#include <iostream>
#include <fstream>
#include "nlohmann/json.hpp"

int main()
{
    const std::string json_str = "{\"data\":1,\"func_code\":10001}";

    try
    {
        nlohmann::json root = nlohmann::json::parse(json_str);
    }
    catch (nlohmann::json::parse_error& e)
    {
        std::cerr << "parse json failed, error message:" << e.what() << std::endl;
    }

    return 0;
}

2.2 创建json对象

通过nlohmann json我们可以很简单就可以创建json对象,比如

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    nlohmann::json root;
    root["pi"] = 3.141;
    root["happy"] = true;
    root["name"] = "Niels";
    root["nothing"] = nullptr;
    root["answer"]["everything"] = 42;
    root["list"] = { 1, 0, 2 };
    root["object"] = { {"currency", "USD"}, {"value", 42.99} };

    return 0;
}

也可以这样

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    nlohmann::json root = {
      {"pi", 3.141},
      {"happy", true},
      {"name", "Niels"},
      {"nothing", nullptr},
      {"answer", {
        {"everything", 42}
      }},
      {"list", {1, 0, 2}},
      {"object", {
        {"currency", "USD"},
        {"value", 42.99}
      }}
    };

    return 0;
}

也可以从输入流中创建json

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    nlohmann::json root;
    std::cin >> root;

    return 0;
}

2.3 json对象序列化为字符串

nlohmann json支持将json对象序列化为字符串,示例代码如下

#include <iostream>
#include <fstream>
#include "nlohmann/json.hpp"

int main()
{
    nlohmann::json root;
    root["pi"] = 3.141;
    root["happy"] = true;
    root["name"] = "Niels";
    root["nothing"] = nullptr;
    root["answer"]["everything"] = 42;
    root["list"] = { 1, 0, 2 };
    root["object"] = { {"currency", "USD"}, {"value", 42.99} };

    std::string json_str = root.dump();

    std::cout << json_str << std::endl;

    return 0;
}

2.4 json对象保存为json文件

#include <iostream>
#include "nlohmann/json.hpp"

int main()
{
    nlohmann::json root;
    root["pi"] = 3.141;
    root["happy"] = true;
    root["name"] = "Niels";
    root["nothing"] = nullptr;
    root["answer"]["everything"] = 42;
    root["list"] = { 1, 0, 2 };
    root["object"] = { {"currency", "USD"}, {"value", 42.99} };

    std::string json_str = root.dump();

    // 写入json文件
    std::ofstream ofs("example.json");
    ofs << json_str;
    ofs.close();

    return 0;
}