JsonCpp 笔记: 读写 Json 文件
完成时间: 2024-04-06
本文主要介绍使用 JsonCpp 读写 Json 文件, JsonCpp 是 C++ 上的一个 Json 处理库
Json 的语法
如果熟悉 Json 语法, 此部分可以跳过
Json 包含两种结构:
- 对象 (object), 它是键值对的集合 (
key:value
) - 有序数组 (array)
结构之间以逗号 ,
分隔, 最后一个结构末尾不能有逗号
对象 (object)
Json 对象中的键值对是无序的 (所以称为 "集合", 数学上的集合是无序的), 包裹在一对花括号 {}
中.
键 (key)
键必须是字符串
{
"name": "Fie",
"gender": "Female"
}
其中 name
和 gender
都是键值对, 之间用逗号分隔, 它们之间没有先后关系, gender
的末尾没有逗号
值 (value)
Fie
和 Female
都是键的值 (value), 它们是字符串. 值的类型可以是:
- 字符串 (string)
- 数值 (number)
- 布尔值 (true, false)
- 空 (null)
- 对象 (object)
- 数组 (array)
Json 支持嵌套, 所以值的类型也可以是对象或数组, 例如
{
"name": "Fie",
"gender": "Female",
"weapon": "Dagger",
"master": {
"name": "Sara Valestein",
"gender": "Female",
"occupation": "Instructor",
"affiliation": "Thors Military Academy",
"weapon": "Sword"
}
}
上面键 master
的值, 又是一个对象
数组 (array)
数组是 值 的 有序 列表 (关键字: 值 & 有序)
{
"likes": [
"Napping",
"Snacking",
"Observing surroundings",
"Practicing swordsmanship",
"Going on missions with friends"
]
}
标准的 Json 语法是不允许数组独立存在的, 因为数组只是值的集合. 所以 Json 可以看作是由若干个 键值对 所组成的对象, 只不过支持嵌套, 值也可以是列表
{
"key1": "string",
"key2": 3.14,
"key3": {
"sub_key": "str1",
"sub_key": "str2"
},
"key4": [
0, 1, 2, 3, 4, 5
]
}
详细内容可参考 json.org
环境配置
安装
此处简单提及一下 Windows 中如何在 Visual Studio Code 上使用 JsonCpp
VS Code 文档推荐我们在 Windows 平台上使用 msys2 安装 GCC 编译器, msys2 是一个 C++ 的包管理软件. 同样地, 我们也用 msys2 安装 jsoncpp
# 搜索 jsoncpp 包
pacman -Ss jsoncpp
# output:
# mingw64/mingw-w64-x86_64-jsoncpp 1.9.5-3
# A C++ library for interacting with JSON (mingw-w64)
# ucrt64/mingw-w64-ucrt-x86_64-jsoncpp 1.9.5-3
# A C++ library for interacting with JSON (mingw-w64)
# clang32/mingw-w64-clang-i686-jsoncpp 1.9.5-3
# A C++ library for interacting with JSON (mingw-w64)
pacman
是 msys2 的包管理命令, 来源于 ArchLinux, 使用上面的语句搜索 JsonCpp 包, 会返回隶属于多个环境的包, 默认情况下我们的 GCC 编译器是安装在 ucrt64 内的, 所以也安装对应的 JsonCpp
pacman -S mingw-w64-ucrt-x86_64-jsoncpp
编译选项
安装好后, 在编译时需要链接 JsonCpp. 在 .vscode
目录内, 有一个 task.json
文件, 它控制了 VS Code 如何执行生成任务. 给 GCC 编译器添加一个链接参数 -ljsoncpp
, 示例如下:
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-l",
"jsoncpp",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
]
添加好后就可以开始学习使用 JsonCpp 了. 如果没有在编译时链接 JsonCpp, 会提示各种 未定义 错误, 例如:
undefined reference to `Json::Value::~Value()'
从文件流中读取
本文只会介绍新式的 API, 老式的方法已不推荐使用. 要在代码中使用 JsonCpp 库, 需要先包含头文件
#include "json/json.h"
以下是一段示例代码
Json::Value root;
std::ifstream ifs;
ifs.open("./example.json");
Json::CharReaderBuilder builder;
JSONCPP_STRING errs;
Json::parseFromStream(builder, ifs, &root, &errs);
cout << root;
JsonCpp 包含命名空间 Json
, 类 Value
表示 Json 对象. 代码中第 1 行是在新建一个 Json 对象
类 CharReaderBuilder
用于创建一个 读取器 (第 5 行代码的工作)
JSONCPP_STRING
是一个 typedef
, 表示 Json::String
对象, 是 JsonCpp 中用于存储字符串的类型, 类似于标准的 std::string
类型
parseFromStream()
方法可以从文件流中读取 Json 数据, 它的函数原型如下:
bool Json::parseFromStream (
CharReader::Factory const & fact,
IStream & sin,
Value * root,
String * errs
)
需要注意的是, parseFromStream()
方法的第一个参数类型是 CharReader::Factory const &
, 而我们构建的读取器 builder
的类型是 CharReaderBuilder
. 这其实是因为 CharReaderBuilder
类是继承自 CharReader::Factory
JsonCpp 重载了 std::cout
方法, 可以直接使用 cout
方法打印 Json 数据 (第 8 行的工作)
修改 Json 数据
从流中读取 Json 文件后, 可以直接使用数组索引的方式修改 Json 数据
假设有如下 Json 文件:
{
"name": "Fie",
"gender": "Female",
"weapon": "Dagger",
"master": {
"name": "Sara Valestein",
"gender": "Female",
"occupation": "Instructor",
"affiliation": "Thors Military Academy",
"weapon": "Sword"
},
"class": "Class VII",
"likes": [
"Napping",
"Snacking",
"Observing surroundings",
"Practicing swordsmanship",
"Going on missions with friends"
]
}
我们希望修改 class
的值为 Class VIII
, 可以直接使用
root["class"] = "Class VIII";
修改数组, 直接使用位置索引即可, 因为数组是有序的, 索引从 0 开始:
root["likes"][1] = "Snacking ^_^";
修改嵌套的 Json 对象与修改二维数组类似:
root["master"]["weapon"] = "Sword >_<";
修改之后的 Json 数据如下:
{
"class" : "Class VIII",
"gender" : "Female",
"likes" :
[
"Napping",
"Snacking ^_^",
"Observing surroundings",
"Practicing swordsmanship",
"Going on missions with friends"
],
"master" :
{
"affiliation" : "Thors Military Academy",
"gender" : "Female",
"name" : "Sara Valestein",
"occupation" : "Instructor",
"weapon" : "Sword >_<"
},
"name" : "Fie",
"weapon" : "Dagger"
}
如果要修改的内容在 Json 中不存在, 则会变成插入
写入文件
假设要将修改后的数据写入 example_new.json
文件中, 示例如下
std::ofstream ofs;
ofs.open("./example_new.json");
Json::StreamWriterBuilder wbuilder;
const std::unique_ptr<Json::StreamWriter> writer(wbuilder.newStreamWriter());
writer->write(root, &ofs);
同样的, 需要新建一个 写入器 wbuilder
, 它是 StreamWriterBuilder
类型的. 使用这个写入器去初始化一个智能指针 writer
, 它是 StreamWriter
类型的, 而方法 newStreamWriter()
会返回一个 StreamWriter
类型的指针
之后使用 write()
方法将数据写回输出流即可
其他
授人以鱼不如授人以渔
JsonCpp 仓库链接: 这里
JsonCpp 文档链接: 这里
JsonCpp 官方是提供了代码示例的, 在仓库的 ./example
目录下, 包括从文件流读写和从代码的 string
对象读写:
- readFromStream
- readFromString
- streamWrite
- stringWrite
JsonCpp 代码示例: 这里
标签:数组,gender,读写,JsonCpp,Json,jsoncpp,Female From: https://www.cnblogs.com/asnelin/p/18117570