JsonCpp的使用及其编码乱码问题

希望我们不仅把编程当成一份工作,更要将其当成一份热爱!!!

                                                                                                                           -----潜意识中有个想成为一名厉害的程序员的梦

1.Jsoncpp环境配置(我用的vs2019,其他版本也同理)

  • 此网址下载其压缩包,解压(GitHub - open-source-parsers/jsoncpp: A C++ library for interacting with JSON.(若网址加载缓慢或打不开,可采用Watt Toolkit加速器(百度安装即可)、或者科学上网)
  • 将图1、图2 的这两个路径的文件,拷贝到你的项目文件中,可以在你的项目文件中新建一个文件,我这里新建了json文件夹(图3)
Image 1Image 2
图1图2
Image
图3
  • 在你的工程中新建文件夹json,并把上面拷贝的文件全部加入
Image
  • 包含 你上述(图3)建的文件夹的路径:
Image
  • 编译后 会出现头文件的报错,把报错的头文件中 json/ 去掉 就好了。

2.Jsoncpp的使用示例

  • 新建.text文档,文本内容如下,编码格式为UTF-8.
{
“name”:“张三”,
“age”:18,
“身高”:1.81,
“生日”:“2002-01-02”,
“学校”:“北大青鸟”,
“专业”:[“厨师”,“挖掘机”],
“单身”:true,
“地址”:null
}
Image
  • 程序源码如下(此代码,存在一点问题,若想直接用正确的请跳到文章末尾。不过跟着我的步骤来,有利于你更加清晰关于编码的问题)
#include <iostream>
#include <fstream>
#include <json.h>

int main() {

    //替换为你的json文件的路径
   std::string path = "C:\\Users\\Hanxiangqian\\Desktop\\秋招\\项目\\tools_study\\tool_study\\json.txt";
    // 打开 JSON 文件
    std::ifstream file(path,std::ifstream::binary);
    if (!file.is_open()) {
        std::cerr << "无法打开文件 data.json" << std::endl;
        return 1;
    }

    // 创建 JSON 解析器
    Json::CharReaderBuilder readerBuilder;
    Json::Value root;
    std::string errs;

    // 读取并解析 JSON 文件
    if (!Json::parseFromStream(readerBuilder, file, &root, &errs)) {
        std::cerr << "解析 JSON 文件失败: " << errs << std::endl;
        return 1;
    }

    // 关闭文件
    file.close();

    // 访问 JSON 数据
    std::string name = root["name"].asString();
    int age = root["age"].asInt();
    double height = root["身高"].asDouble();
    std::string birthday = root["生日"].asString();
    std::string school = root["学校"].asString();
    const Json::Value majors = root["专业"];
    bool single = root["单身"].asBool();
    Json::Value address = root["地址"];

    // 输出 JSON 数据
    std::cout << "Name: " << name << std::endl;
    std::cout << "Age: " << age << std::endl;
    std::cout << "Height: " << height << std::endl;
    std::cout << "Birthday: " << birthday << std::endl;
    std::cout << "School: " << school << std::endl;
    std::cout << "Majors: ";
    for (const auto& major : majors) {
        std::cout << major.asString() << " ";
    }
    std::cout << std::endl;
    std::cout << "Single: " << (single ? "true" : "false") << std::endl;
    std::cout << "Address: " << (address.isNull() ? "null" : address.asString()) << std::endl;

    return 0;
}

  • 运行结果如下:
Image 1Image 2

3.乱码及其编码问题解决

  • 可以看到上述运行结果不太对,先说解决方案

1.代码开头 设置控制台的编码方式为 UTF-8,

// 设置控制台输出为 UTF-8 编码
SetConsoleOutputCP(CP_UTF8);

2.关于中文的键的字符串 前加u8

    double height = root[u8"身高"].asDouble();
    std::string birthday = root[u8"生日"].asString();
    std::string school = root[u8"学校"].asString();
    const Json::Value majors = root[u8"专业"];
    bool single = root[u8"单身"].asBool();
    Json::Value address = root[u8"地址"];

3.运行结果如下:正确

Image 1Image 2
  • 分析一下为什么

1.首先json.txt的文本是以UTF-8的编码方式,被编码为二进制的字节流(所有文件都是以二进制形式进行存储的)存储的。

2.我们在读取文件的时候,实际上读取的也是二进制流。在控制台进行显示的时候,会先对其二进制流进行编码,编码成相应的字符后进行显示,所以如果控制台的编码方式(控制台编码默认为GBK)非utf-8,就会出现乱码的情况。因此设置控制台输出为 UTF-8 编码,以使文本被正常显示。

3.以这行代码举例 double height = root[“身高”].asDouble(); 本来我们是想通过找到 “身高” 这个键来找到 “1.81” 这个数据的。但计算机底层是通过二进制数据来对比键的,这里身高是按照GBK来进行编码的,其对应的二进制是:C9 ED B8 DF。而我们的文档是按照UTF-8 进行编码的,所以文档中 “身高” 对应的二进制是:E8 BA AB E9 AB 98

字符root["身高"]:GBK 编码(这里是采用系统的编码方式)json文件:UTF-8 编码
身高C9 ED B8 DFE8 BA AB E9 AB 98
所以在用 "C9 ED B8 DF" 去找键的话,是找不到的,因此在我们最开始输出的结果中,身高是没有值的。

当我们指定字符串的编码方式为utf-8后:double height = root[u8"身高"].asDouble();

字符root["u8身高"]:UTF-8编码json文件:UTF-8 编码
身高E8 BA AB E9 AB 98E8 BA AB E9 AB 98

此时 通过 E8 BA AB E9 AB 98 来找键,就能找到了。

4.正确的完整版代码如下

#include <iostream>
#include <fstream>
#include <json.h>
#include <Windows.h> // 用于设置控制台编码

int main() {
    // 设置控制台输出为 UTF-8 编码
    SetConsoleOutputCP(CP_UTF8);

   std::string path = "C:\\Users\\Hanxiangqian\\Desktop\\秋招\\项目\\tools_study\\tool_study\\json.txt";
    // 打开 JSON 文件
    std::ifstream file(path,std::ifstream::binary);
    if (!file.is_open()) {
        std::cerr << "无法打开文件 data.json" << std::endl;
        return 1;
    }

    // 创建 JSON 解析器
    Json::CharReaderBuilder readerBuilder;
    Json::Value root;
    std::string errs;

    // 读取并解析 JSON 文件
    if (!Json::parseFromStream(readerBuilder, file, &root, &errs)) {
        std::cerr << "解析 JSON 文件失败: " << errs << std::endl;
        return 1;
    }

    // 关闭文件
    file.close();

    // 访问 JSON 数据
    std::string name = root["name"].asString();
    int age = root["age"].asInt();
    double height = root[u8"身高"].asDouble();
    std::string birthday = root[u8"生日"].asString();
    std::string school = root[u8"学校"].asString();
    const Json::Value majors = root[u8"专业"];
    bool single = root[u8"单身"].asBool();
    Json::Value address = root[u8"地址"];

    // 输出 JSON 数据
    std::cout << "Name: " << name << std::endl;
    std::cout << "Age: " << age << std::endl;
    std::cout << "Height: " << height << std::endl;
    std::cout << "Birthday: " << birthday << std::endl;
    std::cout << "School: " << school << std::endl;
    std::cout << "Majors: ";
    for (const auto& major : majors) {
        std::cout << major.asString() << " ";
    }
    std::cout << std::endl;
    std::cout << "Single: " << (single ? "true" : "false") << std::endl;
    std::cout << "Address: " << (address.isNull() ? "null" : address.asString()) << std::endl;

    return 0;
}


  • 32
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值