一. Json 简介

JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于 JavaScript 的一个子集,但尽管它来源于 JavaScript,但 JSON 是独立于语言的,可以被多种编程语言读取。以下是关于 JSON 的一些关键点:

1. 基本结构

  • 对象:由键值对组成,大括号 {} 包围。
  • 数组:由值的有序集合组成,方括号 [] 包围。
  • 值:可以是字符串、数字、对象、数组、布尔值 (true / false) 或 null

2 语法规则

  • 键值对以 “key”: value 的形式出现,键和值之间用冒号分隔
  • 多个键值对之间用逗号分隔。
  • 所有键都必须是字符串,并且用双引号包围。

3. 示例

{
    "name": "John Doe",
    "age": 30,
    "is_student": false,
    "skills": ["JavaScript", "Python", "C++"],
    "address": {
        "street": "123 Main St",
        "city": "Anytown",
        "state": "CA"
    }
}

4. 用途

  • 数据存储:作为一种数据格式,用于文件和数据库存储。
  • 数据交换:作为 APIs 和网络请求中数据交换的标准格式。
  • 配置文件:用于应用程序的配置信息。

二. JsonCpp 简介

1. 安装

sudo apt install libjsoncpp-dev

由于在环境搭建中已经安装了 JsonCpp,这里不需要再次安装了。

2. 简介

JsonCpp 是一个高性能的 JSON 库,用于处理 JSON 数据。它提供了完整的 JSON 标准支持,包括解析 JSON 字符串、生成 JSON 字符串、读写 JSON 对象和数组等功能。

3. 特点

  • 易于使用:JsonCpp 提供了简单直观的 API,使得在 C++ 程序中处理 JSON 数据变得容易。
  • 高性能:它被设计为高性能,可以快速解析和生成大量 JSON 数据。
  • 跨平台:支持多种操作系统,包括 Windows、Linux 和 macOS。
  • 无依赖:JsonCpp 不依赖于任何外部库,可以轻松集成到任何 C++ 项目中。
  • 完全支持 C++11:利用 C++11 的特性,如智能指针和正则表达式。

4. 使用

4.1 头文件和链接库

在这里插入图片描述

#include <jsoncpp/json/json.h>

程序编译时库的链接

-ljsoncpp

4.2 数据转储

namespace Json {
    enum ValueType {
        nullValue = 0, ///< 'null' value
        intValue, ///< signed integer value
        uintValue, ///< unsigned integer value
        realValue, ///< double value
        stringValue, ///< UTF-8 string value
        booleanValue, ///< bool value
        arrayValue, ///< array value (ordered list)
        objectValue ///< object value (collection of name/value pairs).
    };

    class JSON_API Value {
    public:
        void swap(Value& other);
        void copy(const Value& other);

        // 获取数据接口
        const char* asCString() const;
        String asString() const;
        Int asInt() const;
        UInt asUInt() const;
        Int64 asInt64() const;
        UInt64 asUInt64() const;
        float asFloat() const;
        double asDouble() const;
        bool asBool() const;

        // 判断数据类型
        bool isNull() const;
        bool isBool() const;
        bool isInt() const;
        bool isInt64() const;
        bool isUInt() const;
        bool isUInt64() const;
        bool isIntegral() const;
        bool isDouble() const;
        bool isNumeric() const;
        bool isString() const;
        bool isArray() const;
        bool isObject() const;
        
        // Array-API
        ArrayIndex size() const;
        bool empty() const;
        void clear();
        void resize(ArrayIndex newSize);
        Value& operator[](ArrayIndex index);
        Value& append(const Value& value);
        Value& operator[](const char* key);
        Value& operator[](const String& key);
        void removeMember(const String& key);
        bool isMember(const String& key) const;
        String toStyledString() const;
    }
}

4.3 序列化

namespace Json {
    class JSON_API StreamWriter {
    public:
        virtual int write(Value const& root, OStream* sout) = 0;

        class JSON_API Factory {
        public:
            virtual StreamWriter* newStreamWriter() = 0;
        }
    };
    class streamWriterBuilder : public StreamWriter::Factory {
    public:
        Json::Value settings_;
        StreamWriter* newStreamWriter() const override;
    };
}

4.4 反序列化

namespace Json {
    class JSON_API CharReader {
    public:
        virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, String* errs) = 0;
        
        class JSON_API Factory {
        public:
            virtual CharReader* newCharReader() const = 0;
        }
    };
    class JSON_API CharReaderBuilder : public CharReader::Factory {
    public:
        Json::Value settings_;
        CharReader* newCharReader() const override;
    };
}

三. JsonCpp 使用样例

1. 目录结构

jsoncpp/
|-- main.cc
|-- makefile
|-- serialize.cc
|-- unserialize.cc

2. 项目构建

# makefile
all: main serialize unserialize
main: main.cc
	g++ -o $@ $^ -std=c++17 -ljsoncpp
serialize: serialize.cc
	g++ -o $@ $^ -std=c++17 -ljsoncpp
unserialize: unserialize.cc
	g++ -o $@ $^ -std=c++17 -ljsoncpp

.PHONY: clean
clean:
	rm -f main serialize unserialize

3 样例代码

3.1 序列化

简单的序列化:

// main.cc
#include <iostream>
#include <jsoncpp/json/json.h>

int main(int argc, char* argv[])
{
    Json::Value val;
    val["name"] = "zhangsan";
    val["age"] = 18;
    val["score"].append(95.5);
    val["score"].append(90.5);
    val["score"].append(85.5);
    std::string str = val.toStyledString();
    std::cout << str << std::endl;
    
    return 0;
}

在这里插入图片描述

标准的序列化:

// serialize.cc
#include <iostream>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>

int main(int argc, char* argv[])
{
    Json::Value val;
    val["name"] = "zhangsan";
    val["age"] = 18;
    val["score"].append(95.5);
    val["score"].append(90.5);
    val["score"].append(85.5);

    // 1.实例化建造者对象
    Json::StreamWriterBuilder builder;
    builder["indentation"] = ""; // 关闭缩进
    // 2.通过建造者对象实例化序列化对象
    std::unique_ptr<Json::StreamWriter> sw(builder.newStreamWriter());
    // 3.通过序列化对象进行序列化
    std::stringstream ss;
    int ret = sw->write(val, &ss);
    if (ret != 0) {
        std::cout << "write failed" << std::endl;
        return -1;
    }
    // 4.获取序列化后的字符串
    std::string str = ss.str();
    std::cout << str << std::endl;
    
    return 0;
}

在这里插入图片描述

3.2 反序列化

标准的反序列化:

// unserialize.cc
#include <iostream>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>

int main(int argc, char* argv[])
{
    // 去除所有字符的特殊含义
    std::string str = R"({"age":18,"name":"zhangsan","score":[95.5,90.5,85.5]})";
    // 1.实例化建造者对象
    Json::CharReaderBuilder builder;
    // 2.通过建造者对象实例化反序列化对象
    std::unique_ptr<Json::CharReader> cr(builder.newCharReader());
    // 3.通过反序列化对象进行反序列化
    Json::Value val;
    std::string errors;
    bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &val, &errors);
    if (!ret) {
        std::cout << "parse failed: " << errors << std::endl;
        return -1;
    }
    // 4.获取反序列化后的Json::Value对象
    std::cout << "name: " << val["name"].asString() << std::endl;
    std::cout << "age: " << val["age"].asInt() << std::endl;
    std::cout << "score: ";
    if (!val["score"].isNull() && val["score"].isArray()) {
        int size = val["score"].size();
        for (int i = 0; i < size; ++i) {
            std::cout << val["score"][i].asFloat() << " ";
        }
    }
    std::cout << std::endl;
    
    return 0;
}

在这里插入图片描述

四. JsonCpp 封装

在这里插入图片描述

将 example 文件夹改名为 test,并创建一个新的 example 文件夹并且将 gflags、gtest、spdlog 和 jsoncpp 移动到 example 文件夹下。

在这里插入图片描述

在这里插入图片描述

1. 设计与实现

  • 原因:为了能够在项目中使序列化和反序列化更加便捷。
  • 设计:封装一个 Json 工具类,内部包含两个接口,序列化和反序列化接口。
    • 序列化:输入 Json::Value 对象;输出 Json 格式的字符串。
    • 反序列化:输入 Json 格式的字符串;输入 Json::Value 对象。
// xzyutil.h
#pragma once
#include <iostream>
#include <sstream>
#include <memory>
#include <optional>
#include <jsoncpp/json/json.h>

namespace xzyutil {
    class JSON {
    public:
        // 序列化
        static std::optional<std::string> serialize(const Json::Value& value);
        // 反序列化
        static std::optional<Json::Value> unserialize(const std::string& str);
    };
}
// xzyutil.cc
#include "xzyutil.h"

namespace xzyutil {
    // 序列化
    std::optional<std::string> JSON::serialize(const Json::Value& val) {
        // 1.实例化建造者对象
        Json::StreamWriterBuilder builder;
        builder["indentation"] = "";
        // 2.通过建造者对象实例化序列化对象
        std::unique_ptr<Json::StreamWriter> sw(builder.newStreamWriter());
        // 3.通过序列化对象进行序列化
        std::stringstream ss;
        int ret = sw->write(val, &ss);
        if (ret != 0) {
            std::cout << "序列化失败!" << std::endl;
            return std::optional<std::string>();
        }
        // 4.获取序列化后的字符串
        return ss.str();
    }
    // 反序列化
    std::optional<Json::Value> JSON::unserialize(const std::string& str) {
        // 1.实例化建造者对象
        Json::CharReaderBuilder builder;
        // 2.通过建造者对象实例化反序列化对象
        std::unique_ptr<Json::CharReader> cr(builder.newCharReader());
        // 3.通过反序列化对象进行反序列化
        Json::Value val;
        std::string errors;
        bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &val, &errors);
        if (!ret) {
            std::cout << "反序列化失败!" << std::endl;
            return std::optional<Json::Value>();
        }
        // 4.获取反序列化后的Json::Value对象
        return val;
    }
}

2. 使用

2.1 目录结构

|-- source
|   |-- xzyutil.cc
|   |-- xzyutil.h
|-- test
    |-- jsoncpp
    |   |-- json_test
    |   |-- json_test.cc
    |   |-- makefile

2.2 项目构建

# makefile
json_test: json_test.cc ../../source/xzyutil.cc
	g++ -o $@ $^ -std=c++17 -ljsoncpp

.PHONY: clean
clean:
	rm -f json_test

2.3 代码编写

// json_test.cc
#include "../../source/xzyutil.h"

void serialize_test()
{
    Json::Value val;
    val["name"] = "zhangsan";
    val["age"] = 18;
    val["score"].append(95.5);
    val["score"].append(90.5);
    val["score"].append(85.5);
    std::optional<std::string> str = xzyutil::JSON::serialize(val);
    if (!str.has_value()) {
        std::cout << "序列化失败!" << std::endl;
        return;
    }
    std::cout << str.value() << std::endl;
}

void unserialize_test()
{
    std::string str = R"({"name":"zhangsan","age":18,"score":[95.5,90.5,85.5]})";
    std::optional<Json::Value> val = xzyutil::JSON::unserialize(str);
    if (!val.has_value()) {
        std::cout << "反序列化失败!" << std::endl;
        return;
    }
    std::cout << "name: " << val.value()["name"].asString() << std::endl;
    std::cout << "age: " << val.value()["age"].asInt() << std::endl;
    std::cout << "score: ";
    if (!val.value()["score"].isNull() && val.value()["score"].isArray()) {
        int size = val.value()["score"].size();
        for (int i = 0; i < size; ++i) {
            std::cout << val.value()["score"][i].asFloat() << " ";
        }
    }
    std::cout << std::endl;
}

int main(int argc, char* argv[])
{
    serialize_test();
    unserialize_test();

    return 0;
}

在这里插入图片描述

提交本地代码到远程仓库

在这里插入图片描述

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐