首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【在线五子棋对战】三、Json && JsonCpp的使用

【在线五子棋对战】三、Json && JsonCpp的使用

作者头像
利刃大大
发布2025-06-10 08:28:35
发布2025-06-10 08:28:35
10800
代码可运行
举报
文章被收录于专栏:csdn文章搬运csdn文章搬运
运行总次数:0
代码可运行

Ⅰ. 什么是Json

1、什么是JSON

JSONJavaScrip Object Notation一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的 js 规范) 的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

​ 关于上面的描述可以精简为一句话:Json 是一种数据格式,和语言无关,在什么语言中都可以使用 Json。基于这种通用的数据格式,一般处理两方面的任务:

  1. 组织数据(数据序列化):用于数据的网络传输。
  2. 组织数据(数据序列化):写磁盘文件实现数据的持久化存储。(一般以 .json 作为文件后缀)

Json 中主要有两种数据格式:Json 数组Json 对象,并且这两种格式可以交叉嵌套使用,下面依次介绍下这两种数据格式:

2、Json 数组

Json 数组使用 [] 表示[] 里边是元素,元素和元素之间使用逗号间隔最后一个元素后边没有逗号(不然会出现解析错误),一个 Json 数组中支持同时存在多种不同类型的成员,包括:整形浮点字符串布尔类型json数组json对象空值-null

​ 由此可见 Json 数组比起 C/C++ 数组要灵活很多!

下面给出 Json 数组的定义场景:

Json 数组中的元素数据类型一致

代码语言:javascript
代码运行次数:0
运行
复制
// 整形
[1,2,3,4,5]
// 字符串
["luffy", "sanji", "zoro", "nami", "robin"]

Json 数组中的元素数据类型不一致

代码语言:javascript
代码运行次数:0
运行
复制
[12, 13.34, true, false, "hello,world", null]

Json 数组中的数组嵌套使用

代码语言:javascript
代码运行次数:0
运行
复制
[
    ["cat", "dog", "panda", "beer", "rabbit"],
    ["北京", "上海", "天津", "重庆"],
    ["luffy", "boy", 19]
]

Json 数组和对象嵌套使用

代码语言:javascript
代码运行次数:0
运行
复制
[
    {
        "luffy":{
            "age":19,
            "father":"Monkey·D·Dragon",
            "grandpa":"Monkey D Garp",
            "brother1":"Portgas D Ace",
            "brother2":"Sabo"
        }
    }
]

3、Json 对象

Json 对象使用 {} 来描述,每个 Json 对象中可以存储若干个元素,每一个元素对应一个键值对(key:value 结构),元素和元素之间使用逗号间隔最后一个元素后边没有逗号。对于每个元素中的键值对有以下细节需要注意:

  1. 键值(key)必须是字符串,且位于同一层级的键值不要重复(因为是通过键值取出对应的 value 值)
  2. value 值的类型是可选的,可根据实际需求指定,可用类型包括:整形浮点字符串布尔类型json数组json对象空值-null

比如说使用 Json 对象描述一个人的信息:

代码语言:javascript
代码运行次数:0
运行
复制
{
    "Name":"Ace",
    "Sex":"man",
    "Age":20,
    "Family":{
        "Father":"Gol·D·Roger",
        "Mother":"Portgas·D·Rouge",
        "Brother":["Sabo", "Monkey D. Luffy"]
    },
    "IsAlive":false,
    "Comment":"yyds"
}

4、注意事项

​ 通过上面的介绍可用看到,Json 的结构虽然简单,但是进行嵌套之后就可以描述很复杂的事情,在项目开发过程中往往需要我们根据实际需求自己定义 Json 格式用来存储项目数据。

​ 另外,如果需要将 Json 数据持久化到磁盘文件中,需要注意一个问题:在一个 Json 文件中只能有一个 Json 数组或者 Json 对象的根节点,不允许同时存储多个并列的根节点。 下面举例说明:

❗错误的写法:

代码语言:javascript
代码运行次数:0
运行
复制
// test.json
{
    "name":"luffy",
    "age":19
}
{
    "user":"ace",
    "passwd":"123456"
}

错误原因:在一个 Json 文件中有两个并列的 Json 根节点(并列包含 Json 对象和 Json 对象、Json 对象和 Json 数组、Json 数组和 Json 数组),根节点只能有一个。

🎏正确的写法

代码语言:javascript
代码运行次数:0
运行
复制
// test.json
{
    "Name":"Ace",
    "Sex":"man",
    "Age":20,
    "Family":{
        "Father":"Gol·D·Roger",
        "Mother":"Portgas·D·Rouge",
        "Brother":["Sabo", "Monkey D. Luffy"]
    },
    "IsAlive":false,
    "Comment":"yyds"
}

​ 在上面的例子中通过 Json 对象以及 Json 数组的嵌套描述了一个人的身份信息,并且根节点只有一个就是 Json 对象,如果还需要使用 Json 数组或者 Json 对象描述其他信息,需要将这些信息写入到其他文件中,不要和这个 Json 对象并列写入到同一个文件里边,切记!!!

Ⅱ. JsonCpp

JsonCpp 使用指导

Jsoncpp 库主要是用于实现 Json 格式数据的 序列化反序列化,它实现了将多个数据对象组织成为 Json 格式字符串,以及将 Json 格式字符串解析得到多个数据对象的功能。

注意在编译的时候,记得要指定 jsoncpp,如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
json:json.cpp
	g++ -o $@ $^ -std=c++11 -lboost_system -lpthread -ljsoncpp
1、Json::Value类

Json::Value 是中间的数据存储类,要对数据的序列化和反序列化,都绕不开这个 Json::Value。它要先将数据给存储起来,然后通过内部的层级划分来进行序列化或者反序列化!

代码语言:javascript
代码运行次数:0
运行
复制
class Json::Value
{
    // Value类重载了[]和=,因此所有的赋值和获取数据都可以通过
    Value &operator=(const Value &other);      
    Value& operator[](const std::string& key); // 简单的⽅式完成 val["name"] = "xx";
    Value& operator[](const char* key);
    
    Value removeMember(const char* key); // 移除元素
    
    const Value& operator[](ArrayIndex index) const; // 通常用于Json数组的下标访问,比如val["score"][0]
    Value& append(const Value& value); 				 // Json数组元素只能通过这个接口添加元素,比如val["score"].append(88); 
    ArrayIndex size() const;						 // 获取数组元素个数,比如val["score"].size();
    
    bool isNull(); // ⽤于判断是否存在某个字段
    
    std::string asString() const;  // 转为string,比如string name = val["name"].asString();
    const char* asCString() const; // 转为char* ,比如char *name = val["name"].asCString();
    Int asInt() const;			   // 转为int   ,比如int age = val["age"].asInt();
    float asFloat() const;		   // 转为float ,比如float weight = val["weight"].asFloat();
    bool asBool() const;		   // 转为bool  ,比如bool ok = val["ok"].asBool();
};
2、序列化接口与步骤
代码语言:javascript
代码运行次数:0
运行
复制
class JSON_API StreamWriter 
{
    // 将root这个数据类序列化的写到sout流中
    virtual int write(Value const& root, std::ostream* sout) = 0; 
}
class JSON_API StreamWriterBuilder : public StreamWriter::Factory 
{
    // 工厂类对象函数,用于生产出StreamWriter对象
    virtual StreamWriter* newStreamWriter() const;
}

序列化步骤如下:

  1. 实例化 json::value 对象,将要序列化的数据存储到该对象中
  2. 实例化一个 StreamWriterBuilder 工厂类对象
  3. 通过 StreamWriterBuilder 对象来生产一个 StreamWriter 对象
  4. 通过 StreamWriter 对象实现序列化
3、反序列化接口与步骤
代码语言:javascript
代码运行次数:0
运行
复制
class JSON_API CharReader 
{
    // 从beginDoc到endDoc流中提取数据并且反序列化到root中,如果出错了用errs这个输出型参数获取错误码
    virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, std::string* errs) = 0;
}
class JSON_API CharReaderBuilder : public CharReader::Factory 
{
    // 工厂类对象函数,用于生产出CharReader对象
    virtual CharReader* newCharReader() const;
}

反序列化步骤如下:

  1. 实例化一个 CharReaderBuilder 工厂类对象
  2. 使用 CharReaderBuilder 工厂类来生产一个 CharReader 类对象
  3. 定义一个 Json::Value 类对象存储反序列化后的数据
  4. 使用 CharReader 类对象进行 json 格式字符串 str 的反序列化
  5. 逐个元素去访问 Json::Value 中的数据,记得要用转换函数进行转换类型
4、测试代码
代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>

// 序列化
std::string serialize()
{
    // 1.实例化json::value对象,将要序列化的数据存储到该对象中
    Json::Value root;
    root["姓名"] = "liren";
    root["年龄"] = 1314;
    root["成绩"].append(100);
    root["成绩"].append(200);
    root["成绩"].append(300);

    // 2.实例化工厂类对象StreamWriterBuilder
    Json::StreamWriterBuilder swb;

    // 3.通过 StreamWriterBuilder 来生产一个 StreamWriter 对象,最好用智能指针管理
    std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());

    // 4.通过 StreamWriter 对象实现序列化
    std::stringstream ss;
    int n = sw->write(root, &ss);
    if(n != 0)
    {
        std::cout << "json serialize fail!" << std::endl;
        return "";
    }
    std::cout << ss.str() << std::endl;
    return ss.str();
}

void unserialize(const std::string& str)
{
    // 1. 实例化一个CharReaderBuilder工厂类对象
    Json::CharReaderBuilder crb;

    // 2. 使用CharReaderBuilder工厂类来生产一个CharReader类对象,最好用智能指针管理
    std::unique_ptr<Json::CharReader> cr(crb.newCharReader());

    // 3. 定义一个Json::Value类对象存储反序列化后的数据
    Json::Value root;

    // 4. 使用CharReader类对象进行json格式字符串str的反序列化
    std::string err;
    bool n = cr->parse(str.c_str(), str.c_str() + str.size(), &root, &err);
    if(n == false)
    {
        std::cout << "json unserialize fail!" << std::endl;
        return;
    }

    // 5. 逐个元素去访问Json::Value中的数据,记得要用转换函数进行转换类型
    std::cout << root["姓名"].asString() << std::endl;
    std::cout << root["年龄"].asInt() << std::endl;
    int size = root["成绩"].size();
    for(int i = 0; i < size; ++i)
    {
        std::cout << root["成绩"][i].asInt() << std::endl;
    }
}

int main()
{
    std::string str = serialize();
    unserialize(str);
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Ⅰ. 什么是Json
    • 1、什么是JSON
    • 2、Json 数组
    • 3、Json 对象
    • 4、注意事项
  • Ⅱ. JsonCpp
    • JsonCpp 使用指导
    • 1、Json::Value类
    • 2、序列化接口与步骤
    • 3、反序列化接口与步骤
    • 4、测试代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档