C/C++ json库

打印 上一主题 下一主题

主题 528|帖子 528|积分 1584

一、介绍

1.1 json 介绍



  • 官网:http://www.json.org/json-zh.html
  • JSON是什么?如何正确明白?
二、C/C++ json 库选型

2.1 选型范围



  • 资料

    • 官网:http://www.json.org/json-zh.html
    • 开源库比较:https://github.com/miloyip/nativejson-benchmark
    • C++中json库的选择
    • C/C++ 开源 JSON 程序库性能及标准符合水平评测

  • 开源库

    • Rapidjson、Rapidjson_FullPrec、Rapidjson_AutoUTF
    • nlohmann / json
    • jsoncpp


  • 结论:

    • 注重最佳性能,选 Rapidjson (cereal序列化库使用)
    • 注重易用性,选 jsoncpp (ros 使用)、nlohmann / json


2.2 jsoncpp



  • 精度控制:precision

    • 15,16,17:原值会变
    • 0-14:原值不变的情况下,四舍五入

2.2.2 jsoncpp 编译和交叉编译



  • jsoncpp 的编译和交叉编译
  • 编译
    1. mkdir build; cd build
    2. cmake -DCMAKE_BUILD_TYPE=Release \
    3. -DBUILD_SHARED_LIBS=ON \
    4. -DCMAKE_INSTALL_PREFIX=`pwd`/result \
    5. -DJSONCPP_WITH_TESTS=OFF \ ..
    6. make install -j4
    复制代码
  • 交叉编译
    1. mkdir build; cd build
    2. cmake -DCMAKE_BUILD_TYPE=Release \
    3. -DBUILD_SHARED_LIBS=ON \
    4. -DCMAKE_INSTALL_PREFIX=`pwd`/result \
    5. -DJSONCPP_WITH_TESTS=OFF \ ..
    6. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \ ..
    7. make install -j4
    8. # toolchain.cmake 定义交叉编译环境变量
    9. SET(CMAKE_SYSROOT "/opt/fslc-x11/2.4.4/sysroots/armv7at2hf-neon-fslc-linux-gnueabi")
    10. set(CMAKE_SYSTEM_NAME Linux)
    11. set(CMAKE_SYSTEM_PROCESSOR arm)
    12. set(TOOLS /opt/fslc-x11/2.4.4/sysroots/x86_64-fslcsdk-linux/usr/bin/arm-fslc-linux-gnueabi)
    13. set(CMAKE_C_COMPILER "${TOOLS}/arm-fslc-linux-gnueabi-gcc")
    14. set(CMAKE_CXX_COMPILER "${TOOLS}/arm-fslc-linux-gnueabi-g++")
    15. set(CMAKE_AR "${TOOLS}/arm-fslc-linux-gnueabi-ar")
    复制代码
  • include/json
  • lib/cmake/xxx.cmake
  • lib/pkgconfig/jsoncpp.pc
  • pkgconfig
    1. mayue@PC-MAYUE:/mnt/d/hik/opensource/jsoncpp-1.9.5/build/result/lib$ cat pkgconfig/jsoncpp.pc
    2. prefix=/mnt/d/hik/opensource/jsoncpp-1.9.5/build/result
    3. exec_prefix=/mnt/d/hik/opensource/jsoncpp-1.9.5/build/result
    4. libdir=${exec_prefix}/lib
    5. includedir=${prefix}/include
    6. Name: jsoncpp
    7. Description: A C++ library for interacting with JSON
    8. Version: 1.9.5
    9. URL: https://github.com/open-source-parsers/jsoncpp
    10. Libs: -L${libdir} -ljsoncpp
    11. Cflags: -I${includedir}
    复制代码
指定连接静态库
  1. g++ jsoncpp-test.cpp -I./include -L ./lib -l:libjsoncpp.a
复制代码
2.3 rapidjson



  • https://rapidjson.org/zh-cn/
  • https://github.com/Tencent/rapidjson

2.4 nlohmann/json



  • https://github.com/nlohmann/json
  • nlohmann入门使用总结
2.5 sonic-cpp



  • 当前仅支持amd64
  • 开源 C++ JSON 库 sonic-cpp解析性能为 rapidjson 的 2.5 倍
  • 性能提升 2.5 倍!字节开源高性能 C++ JSON 库 sonic-cpp
五、常见问题

5.1 jsoncpp 中关于浮点数的控制和中文显示问题



  • jsoncpp 中关于浮点数的控制和中文显示问题
5.2 jsoncpp序列化double类型时精度损失问题的解决办法



  • jsoncpp序列化double类型时精度损失问题的解决办法
解决办法1:此法不需要改源码,使用StreamWriterBuilder举行序列化
  1. #include <json/json.h>
  2. #include <json/writer.h>
  3. #include <iostream>
  4. #include <string>
  5. void test_precision(int precision)
  6. {
  7.     Json::Value root;
  8.     root["pi"] = 3.1415926;
  9.     root["count"] = 43.32558674566;
  10.     Json::StreamWriterBuilder builder;
  11.     //设置精度 注意这个默认设置的是数字总长度
  12.     //如果想设置小数点后的位数需设置precisionType为decimal
  13.     builder.settings_["precision"] = precision;
  14.     //设置精度类型 只可设置2种字符串 significant精度位数为数字总长度(jsoncpp默认为此类型) decimal精度位数为小数点后的长度
  15.     builder.settings_["precisionType"] = "decimal";
  16.     // 设置输出为紧凑格式,不带换行和空格
  17.     builder["commentStyle"] = "None";   // 防止输出注释,默认就是none
  18.     builder["indentation"] = "";        // 空字符串表示不缩进
  19.     std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
  20.     std::ostringstream oss;
  21.     writer->write(root, &oss);
  22.     std::string jsonText = oss.str();
  23.     // 输出 JSON 字符串
  24.     std::cout << "specified precision: " << precision << ", content:" << jsonText << std::endl;
  25. }
  26. int main() {
  27.     for(int i=17; i>=0; i--)
  28.     {
  29.         test_precision(i);
  30.     }
  31.     return 0;
  32. }
复制代码
  1. specified precision: 17, content:{"count":43.32558674565999723,"pi":3.14159260000000007}
  2. specified precision: 16, content:{"count":43.3255867456599972,"pi":3.1415926000000001}
  3. specified precision: 15, content:{"count":43.325586745659997,"pi":3.1415926}
  4. specified precision: 14, content:{"count":43.32558674566,"pi":3.1415926}
  5. specified precision: 13, content:{"count":43.32558674566,"pi":3.1415926}
  6. specified precision: 12, content:{"count":43.32558674566,"pi":3.1415926}
  7. specified precision: 11, content:{"count":43.32558674566,"pi":3.1415926}
  8. specified precision: 10, content:{"count":43.3255867457,"pi":3.1415926}
  9. specified precision: 9, content:{"count":43.325586746,"pi":3.1415926}
  10. specified precision: 8, content:{"count":43.32558675,"pi":3.1415926}
  11. specified precision: 7, content:{"count":43.3255867,"pi":3.1415926}
  12. specified precision: 6, content:{"count":43.325587,"pi":3.141593}
  13. specified precision: 5, content:{"count":43.32559,"pi":3.14159}
  14. specified precision: 4, content:{"count":43.3256,"pi":3.1416}
  15. specified precision: 3, content:{"count":43.326,"pi":3.142}
  16. specified precision: 2, content:{"count":43.33,"pi":3.14}
  17. specified precision: 1, content:{"count":43.3,"pi":3.1}
  18. specified precision: 0, content:{"count":43,"pi":3}
复制代码


  • 精度控制:precision

    • 15,16,17:原值会变、四舍五入
    • 0-14:原值不变的情况下,四舍五入

  • 特别注意:精度设置肯定要大于你需求的精度位数,好比需要三位可以设置4位或5位,因为最后一位可能会不准(做了四舍五入)
不敷之处:
StreamWriterBuilder序列化的字符串是可读情势的,就像上面的输出,是有换行和缩进的(转换效率会比FastWrite低),我的服务端代码里实在不需要转换json为可读的,更需要的是效率,以是还有下面一种方法改FasetWrite源码
解决办法2:此法需要改源码,使用FastWriter举行序列化


  • 注意:需升级jsoncpp到最新版本1.9.5版本
  • 修改源码(writer.h):FastWriter类新增2个成员变量(precision_和precisionType_)和成员函数(set_precision和set_precisionType)
    1. #if defined(_MSC_VER)
    2. #pragma warning(push)
    3. #pragma warning(disable : 4996) // Deriving from deprecated class
    4. #endif
    5. class JSON_API FastWriter
    6.     : public Writer {
    7. public:
    8.   FastWriter();
    9.   ~FastWriter() override = default;
    10.   void enableYAMLCompatibility();
    11.   /** \brief Drop the "null" string from the writer's output for nullValues.
    12.    * Strictly speaking, this is not valid JSON. But when the output is being
    13.    * fed to a browser's JavaScript, it makes for smaller output and the
    14.    * browser can handle the output just fine.
    15.    */
    16.   void dropNullPlaceholders();
    17.   void omitEndingLineFeed();
    18. public: // overridden from Writer
    19.   String write(const Value& root) override;
    20.   //设置精度位数
    21.   void set_precision(unsigned int precision) { precision_ = (precision > 17)?17:precision; };
    22.   //设置精度类型 默认为数字总长
    23.   //入参:isDecimal true表示类型为小数点后长度 false表示类型为数字总长
    24.   void set_precisionType(bool isDecimal) { isDecimal ? (precisionType_ = PrecisionType::decimalPlaces) : (precisionType_ = PrecisionType::significantDigits); };
    25. private:
    26.   void writeValue(const Value& value);
    27.   String document_;
    28.   bool yamlCompatibilityEnabled_{false};
    29.   bool dropNullPlaceholders_{false};
    30.   bool omitEndingLineFeed_{false};
    31.   int precision_{ 17 };//精度位数 默认17位
    32.   PrecisionType precisionType_{ PrecisionType::significantDigits };//精度类型 默认为数字总长
    33. };
    34. #if defined(_MSC_VER)
    35. #pragma warning(pop)
    36. #endif
    复制代码
  • 修改源码(json_writer.cpp):只修改了1行代码,FastWriter::writeValue函数中case realValue的处理中调用的valueToString新增了2个参数传递(源码中没有传递用的函数默认值,现在传了而且可以通过新增的2个成员函数举行设置)
    1. void FastWriter::writeValue(const Value& value) {
    2.   switch (value.type()) {
    3.   case nullValue:
    4.     if (!dropNullPlaceholders_)
    5.       document_ += "null";
    6.     break;
    7.   case intValue:
    8.     document_ += valueToString(value.asLargestInt());
    9.     break;
    10.   case uintValue:
    11.     document_ += valueToString(value.asLargestUInt());
    12.     break;
    13.   case realValue:
    14.     //这里原先是document_ += valueToString(value.asDouble());
    15.     //因为后2个参数没传,所以用的函数默认值即精度位数=17,精度类型=PrecisionType::significantDigits
    16.     //修改后 现在会传这2个参数,具体值可以通过新增加的2个成员函数设置
    17.     document_ += valueToString(value.asDouble(), precision_, precisionType_);
    18.     break;
    19.   case stringValue: {
    20.     // Is NULL possible for value.string_? No.
    21.     char const* str;
    22.     char const* end;
    23.     bool ok = value.getString(&str, &end);
    24.     if (ok)
    25.       document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
    26.     break;
    27.   }
    28.   case booleanValue:
    29.     document_ += valueToString(value.asBool());
    30.     break;
    31.   case arrayValue: {
    32.     document_ += '[';
    33.     ArrayIndex size = value.size();
    34.     for (ArrayIndex index = 0; index < size; ++index) {
    35.       if (index > 0)
    36.         document_ += ',';
    37.       writeValue(value[index]);
    38.     }
    39.     document_ += ']';
    40.   } break;
    41.   case objectValue: {
    42.     Value::Members members(value.getMemberNames());
    43.     document_ += '{';
    44.     for (auto it = members.begin(); it != members.end(); ++it) {
    45.       const String& name = *it;
    46.       if (it != members.begin())
    47.         document_ += ',';
    48.       document_ += valueToQuotedStringN(name.data(), name.length());
    49.       document_ += yamlCompatibilityEnabled_ ? ": " : ":";
    50.       writeValue(value[name]);
    51.     }
    52.     document_ += '}';
    53.   } break;
    54.   }
    55. }
    复制代码
  • 需要重新编译库,然后demo验证,使用的代码:
    1. #include <json/json.h>
    2. #include <json/writer.h>
    3. #include <iostream>
    4. #include <string>
    5. void test_precision(int precision)
    6. {
    7.     Json::Value obj;
    8.     Json::FastWriter write;
    9.     write.set_precision(precision);
    10.     write.set_precisionType(true);
    11.     obj["d"] = 2.1;
    12.     obj["d2"] = 9.111;
    13.     obj["d3"] = 9.123456789;
    14.     auto rtn = write.write(obj);
    15.     std::cout << "specified precision: " << precision << ", rtn:" << rtn << std::endl;
    16. }
    17. int main() {
    18.     for(int i=17; i>=0; i--)
    19.     {
    20.         test_precision(i);
    21.     }
    22.     return 0;
    23. }
    复制代码
    1. specified precision: 17, rtn:{"d":2.10000000000000009,"d2":9.11100000000000065,"d3":9.12345678900000046}
    2. specified precision: 16, rtn:{"d":2.1000000000000001,"d2":9.1110000000000007,"d3":9.1234567890000005}
    3. specified precision: 15, rtn:{"d":2.1,"d2":9.111000000000001,"d3":9.123456789}
    4. specified precision: 14, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}
    5. specified precision: 13, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}
    6. specified precision: 12, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}
    7. specified precision: 11, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}
    8. specified precision: 10, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}
    9. specified precision: 9, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}
    10. specified precision: 8, rtn:{"d":2.1,"d2":9.111,"d3":9.12345679}
    11. specified precision: 7, rtn:{"d":2.1,"d2":9.111,"d3":9.1234568}
    12. specified precision: 6, rtn:{"d":2.1,"d2":9.111,"d3":9.123457}
    13. specified precision: 5, rtn:{"d":2.1,"d2":9.111,"d3":9.12346}
    14. specified precision: 4, rtn:{"d":2.1,"d2":9.111,"d3":9.1235}
    15. specified precision: 3, rtn:{"d":2.1,"d2":9.111,"d3":9.123}
    16. specified precision: 2, rtn:{"d":2.1,"d2":9.11,"d3":9.12}
    17. specified precision: 1, rtn:{"d":2.1,"d2":9.1,"d3":9.1}
    18. specified precision: 0, rtn:{"d":2,"d2":9,"d3":9}
    复制代码
C++ json序列化库有哪些,哪个性能最好
C++中有多种JSON序列化库可供选择,包罗但不限于以下几种:

  • Rapidjson:这是一个非常流行的C++ JSON库,以其高性能著称,由腾讯团队开发 。
  • nlohmann/json:这是一个现代的、基于C++11的JSON库,以其易用性和直观的接口而受到很多C++程序员的青睐 。
  • sonic-cpp:由字节跳动STE团队和服务框架团队共同研发的高效JSON库,它利用CPU硬件特性和向量化编程,大幅提高了序列化和反序列化的性能。据报道,其解析性能是rapidjson的2.5倍 。
  • JsonCpp:这是一个成熟的库,提供了丰富的功能来处理JSON数据。
  • simdjson:这是一个使用SIMD指令集来加快解析的库,它提供了快速的解析性能,但不支持修改解析后的JSON布局 。
  • yyjson:这是一个追求解析性能的库,使用链表布局,但在查找数据时性能较差 。
在这些库中,sonic-cpp 被报道为性能最好的库,它不仅提供了高效的解析性能,还解决了其他一些库的缺点,如simdjson和yyjson的问题,并支持高效的增删改查利用 。别的,sonic-cpp已经在字节跳动的多个核心业务中大规模使用,并通过了工程化的磨练 。
假如您对性能有极高的要求,sonic-cpp可能是一个不错的选择。然而,选择哪个库还应考虑其他因素,如易用性、社区支持、库的活跃度和维护情况。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表