首页 前端知识 JsonCpp--快速上手使用C 对json文件的读写(Linux)

JsonCpp--快速上手使用C 对json文件的读写(Linux)

2024-10-15 23:10:16 前端知识 前端哥 381 375 我要收藏

前言

  • 由于原生态的C++库并不支持JSON文件的直接读写,故本文引入JsonCpp库来辅助我们对JSON文件进行读写

JSON简介

  • JSON (JavaScript Object Notation),是一种轻量级数据交换格式。
  • JSON基于两种结构
    • 键值对(A collection of name/value pairs)
    • 值有序链表(An ordered list of values)
  • 在JSON中,通常有一下几种形式:
    • object:一种无序的键-值(key:value)配对。键都代表着一个JSON的字符串,而值可以是任意类型
      {
      "student":{
      "name":"Lihua",
      "age":20,
      "married":false
      }
      }
      复制
    • array:是一个值的有序链表,可以存储多种类型。
      ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
      复制

JsonCpp简介

  • JsonCpp是一个C++库,允许操作JSON值,包括对字符串的序列化和反序列化。它还可以在非序列化/序列化步骤中保留现有注释,使其成为存储用户输入文件的方便格式。

通过apt一键安装JsonCpp

  • JsonCpp有多种下载方法,这里我们使用较为简单的软件包安装(ubuntu及其其他Debian Linux版本)
    sudo apt-get install libjsoncpp-dev
    复制
  • 下载后使用JsonCpp只需包含其头文件即可
    #include <jsoncpp/json/json.h>
    复制
  • 编译只需要添加标志位-ljsoncpp
    g++ -o excutable_name source.cpp -ljsoncpp
    复制
  • 在CMakeLists.txt中配置:
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(JSONCPP jsoncpp)
    include_directories(${JSONCPP_LIBRARIES})
    target_link_libraries(${PROJECT_NAME} ${JSONCPP_LIBRARIES})
    复制

前置知识

Stream Classes in C++
  • 概念:Stream(流)是一种电脑对输入/输出处理的代表方式。
  • 而fstream提供了一系列库和方法来处理文件(file)
    • ofstream:输出流(output stream),创建文件和向文件写入数据
    • ifstream:输入流(input stream),从文件读取数据并且展示他们
    • fstream:文件流(file stream),定义了一些文件操作类常用的流,它有上述两种流的能力

一个例子快速入门

  • 创建一个alice.json文件
    {
    "book":"Alice in Wonderland",
    "year":1865,
    "characters":
    [
    {"name":"Jabberwock", "chapter":1},
    {"name":"Cheshire Cat", "chapter":6},
    {"name":"Mad Hatter", "chapter":7}
    ]
    }
    复制
  • 读取json文件
    #include <iostream>
    #include <fstream>
    #include <jsoncpp/json/json.h>
    using namespace std;
    int main() {
    ifstream ifs("alice.json");
    Json::Reader reader;
    Json::Value obj;
    reader.parse(ifs, obj); // reader can also read strings
    cout << "Book: " << obj["book"].asString() << endl;
    cout << "Year: " << obj["year"].asUInt() << endl;
    const Json::Value& characters = obj["characters"]; // array of characters
    for (int i = 0; i < characters.size(); i++){
    cout << " name: " << characters[i]["name"].asString();
    cout << " chapter: " << characters[i]["chapter"].asUInt();
    cout << endl;
    }
    }
    复制
  • 输出:
    Book: Alice in Wonderland
    Year: 1865
    name: Jabberwock chapter: 1
    name: Cheshire Cat chapter: 6
    name: Mad Hatter chapter: 7
    复制

JsonCpp的三大主要类别

1.Json::Value
  • 说明:代表一个JSON值(value)类型
  • 注意事项:
    1. 当你需要从JSON对象中提取原始数据(如字符串)时,应使用.asString(),.asInt()等方法,而不是直接访问成员。
    2. 如果尝试将错误的类型转换为数值类型,如将字符串转换为整数,将会抛出异常。
  • 常用方法:
    • isObject(), isArray(), isString(), isBool(), isNumber(): 这些方法用于检查Json::Value的类型。
    • getObject(), getArray(), getString(), getBool(), getUInt(): 这些方法用于获取相应的类型数据,如果类型不匹配,这些方法会抛出异常。
    • toStyledString(): 将JSON对象转换为格式化的字符串。
    • append: 向数组类型的JSON值添加一个元素。
    • put: 向对象类型的JSON值添加或修改一个成员。
    • remove: 从对象中移除一个成员。
  • 例子
    #include <jsoncpp/json/json.h>
    #include <iostream>
    int main() {
    // 创建一个Json::Value对象,初始化为null
    Json::Value nullValue;
    std::cout << nullValue.toStyledString() << std::endl; // 输出: null
    // 创建一个Json::Value对象并设置为对象类型
    Json::Value rootValue;
    rootValue["name"] = "John Doe";
    rootValue["age"] = 30;
    rootValue["isStudent"] = false;
    // 输出整个对象
    std::cout << rootValue.toStyledString() << std::endl;
    // 提取对象中的值----注意事项1
    std::string name = rootValue["name"].asString();
    int age = rootValue["age"].asInt();
    bool isStudent = rootValue["isStudent"].asBool();
    std::cout << "Name: " << name << std::endl;
    std::cout << "Age: " << age << std::endl;
    std::cout << "Is Student: " << std::boolalpha << isStudent << std::endl;
    // 修改对象中的值
    rootValue["age"] = 31; // 更新年龄
    rootValue.remove("isStudent"); // 移除isStudent键
    // 添加一个数组类型的值
    Json::ValueArray hobbies;
    hobbies.append("Reading");
    hobbies.append("Swimming");
    rootValue["hobbies"] = hobbies;
    // 输出修改后的对象
    std::cout << rootValue.toStyledString() << std::endl;
    return 0;
    }
    复制
  • 一个特殊例子----当我们有一个嵌套例子时,我们要通过value[arraykey][index][subkey]来访问其内容
    {
    "media": [
    {
    "book"
    },
    {
    "title": "The Great Gatsby",
    "author": "F. Scott Fitzgerald"
    },
    {
    "movie"
    },
    {
    "music"
    }
    ]
    }
    复制
    // 例如,我们要访问media数组中的第二个元素(索引为1),其title键的值
    std::string title = arrayOfObjects[1]["title"].asString();
    复制
2.Json::Reader
  • 说明:提供了一种强力的读取JSON文件的手段
  • 注意事项
    • 确保JSON字符串或文件内容是有效的,否则Json::Reader在解析时会抛出异常。
    • 使用Json::Reader时,字符串字面量中的特殊字符(如引号和反斜杠)需要正确转义。例如,如果JSON中的字符串包含引号,你应该使用转义引号"。
  • 常用方法:
    • parse: 这是主要的解析方法,接受一个std::string或std::istream作为输入,并返回一个Json::Value对象。
    • parseFromFile: 解析一个JSON文件,返回一个Json::Value对象。
    • isValid: 检查JSON字符串是否有效。
    • getError: 获取解析过程中的错误信息。
  • 下面是一个使用Json::Reader解析JSON字符串的例子:
    #include <jsoncpp/json/json.h>
    #include <iostream>
    #include <fstream>
    int main() {
    // 创建一个Json::Value对象,用于存储解析后的数据
    Json::Value rootValue;
    // 创建一个JSON字符串
    std::string jsonString = "{\"name\":\"John Doe\", \"age\":30, \"isStudent\":false}";
    // 创建一个Json::Reader对象
    Json::Reader reader;
    // 尝试解析JSON字符串
    bool parsingSuccessful = reader.parse(jsonString, rootValue);
    if (parsingSuccessful) {
    // 解析成功,打印解析后的值
    std::cout << "Name: " << rootValue["name"].asString() << std::endl;
    std::cout << "Age: " << rootValue["age"].asInt() << std::endl;
    std::cout << "Is Student: " << rootValue["isStudent"].asBool() << std::endl;
    } else {
    // 解析失败,打印错误信息
    std::cout << "Failed to parse JSON: " << reader.getError() << std::endl;
    }
    return 0;
    }```
    复制
  • 当然我们也可以使用ifstream配合使用Json::Reader
    #include <jsoncpp/json/json.h>
    #include <iostream>
    #include <fstream>
    int main() {
    // 创建一个Json::Value对象,用于存储解析后的数据
    Json::Value rootValue;
    // 打开JSON文件
    std::ifstream file("example.json");
    if (!file.is_open()) {
    std::cerr << "Error opening file" << std::endl;
    return 1;
    }
    // 创建一个Json::Reader对象
    Json::Reader reader;
    // 尝试解析JSON文件
    bool parsingSuccessful = reader.parse(file, rootValue, true);
    file.close();
    if (parsingSuccessful) {
    // 解析成功,打印解析后的值
    std::cout << "Name: " << rootValue["name"].asString() << std::endl;
    std::cout << "Age: " << rootValue["age"].asInt() << std::endl;
    } else {
    // 解析失败,打印错误信息
    std::cout << "Failed to parse JSON: " << reader.getFormattedErrorMessages() << std::endl;
    }
    return 0;
    }
    复制
3.Json::Writer
  • 注意Json::Writer是一个抽象类,其中包含了下面两个类
    • FastWriter:生成未格式化的、非人类可读的文档。所有内容都将写在一行中。
    • StyledWriter:生成格式化的可读文档,类似于运算符<<,但缩进较少,没有空行。
  • 这里介绍FastWriter,以下是FastWriter常用的方法:
    // omit the word "null" when printing null values
    // this contradicts the JSON standard, but accepted by JavaScript
    // this function is not available in old versions
    void dropNullPlaceholders();
    // don't add newline as last character
    // this function is not available in old versions
    void omitEndingLineFeed();
    // print space after ":" in objects
    void enableYAMLCompatibility();
    // write JSON object to a string
    virtual std::string write(const Value &root);
    复制
  • 使用例子
    #include <jsoncpp/json/json.h>
    #include <iostream>
    int main() {
    // 创建一个Json::Value对象,用于存储要写入的数据
    Json::Value rootValue;
    rootValue["name"] = "John Doe";
    rootValue["age"] = 30;
    rootValue["isStudent"] = false;
    // 创建一个Json::FastWriter对象
    Json::FastWriter writer;
    // 写入Json::Value对象到字符串
    std::string jsonString = writer.write(rootValue);
    // 输出JSON字符串
    std::cout << jsonString << std::endl;
    return 0;
    }
    复制


综合使用

  • 假设我们有一个巨大的数据需要通过JSON文件存储,并在另一个节点读取它
#include <iostream>
#include <sstream>
#include <fstream>
#include <jsoncpp/json/json.h>
class JSON
{
public:
void json_writer(Json::Value context,const std::string& open_file_path);
void json_reader(const std::string& open_file_path);
private:
bool is_file_empty(std::ifstream& pFile);
std::string file_name="example.json";
};
bool JSON::is_file_empty(std::ifstream& pFile)
//判断文件是否非空
{
return pFile.peek() == std::ifstream::traits_type::eof();
}
void JSON::json_writer(Json::Value context,const std::string& open_file_path)
//使用Json::FastWriter写入文件
{
if(context.isNull())
{
std::cout << "写入的内容是空的" << std::endl;
return ;
}
//判断文件是否为空
std::ifstream file_(open_file_path);
if (!is_file_empty(file_))
{
std::cout << "文件不为空,是否选择覆盖?(y/n)" << std::endl;
char userInput;
std::cin >> userInput;
if (userInput == 'y' || userInput == 'Y')
{
std::cout << "用户选择覆盖。" << std::endl;
} else if (userInput == 'n' || userInput == 'N')
{
std::cout << "用户选择不覆盖。" << std::endl;
return;
} else
{
std::cout << "无效的输入。请输入 'y' 或 'n'。" << std::endl;
return;
}
}
Json::FastWriter write;
auto str = context.toStyledString();
std::ofstream ofss;
ofss.open(open_file_path); //如果文件不存在则创建该文件
ofss << str;
ofss.close();
std::cout << "写入成功!" << std::endl;
}
void JSON::json_reader(const std::string& open_file_path)
//使用Json::Reader读取文件
{
std::ifstream ifs;
ifs.open(open_file_path);
std::stringstream buffer;
buffer << ifs.rdbuf();
ifs.close();
auto str = buffer.str();
Json::Reader reader;
Json::Value value;
if (reader.parse(str, value))
{
// 确保JSON结构中存在"coordinates"数组
if (value.isArray() && value.size() > 0)
{
for (const Json::Value& coordinate : value)
{
// 提取x和y值
int x = coordinate["x"].asInt();
int y = coordinate["y"].asInt();
std::cout << "Coordinate x: " << x << ", y: " << y << std::endl;
}
}else
{
std::cerr << "JSON does not contain a 'coordinates' array." << std::endl;
}
}else
{
std::cerr << "Failed to parse JSON." << std::endl;
}
}
Json::Value createLargeCoordinateArray()
//创建一个存储多元数据的Json::Value
{
Json::Value coordinates;
// 填充坐标数组
for (int i = 0; i < 100; ++i)
{
Json::Value coordinate;
coordinate["x"] = i;
coordinate["y"] = i * 2;
// 添加更多的修饰符和数据
coordinate["linear_X"] = static_cast<int>(i * 0.1);
coordinate["angular_Z"] = static_cast<int>(i * 0.2);
coordinates.append(coordinate);
}
return coordinates;
}
int main()
{
JSON json=JSON();
Json::Value context=createLargeCoordinateArray();
std::string file_path="example3.json";
json.json_writer(context,file_path);
json.json_reader(file_path);
return 0;
}
复制

参考文章

  • https://www.json.org/json-en.html
  • https://chromium.googlesource.com/external/github.com/open-source-parsers/jsoncpp/+/c21b4bbfdb17713af9bcd194106f69aaa289e72b/README.md
  • https://www.cnblogs.com/DswCnblog/p/6678708.html
  • https://en.wikibooks.org/wiki/JsonCpp#With_apt_or_apt-get
  • https://www.simplilearn.com/tutorials/cpp-tutorial/ifstream-in-cpp
  • https://www.daniweb.com/programming/software-development/threads/250669/check-if-file-is-empty
  • https://stackoverflow.com/questions/2390912/checking-for-an-empty-file-in-c
  • https://www.cnblogs.com/zipxzf/articles/14909393.html
转载请注明出处或者链接地址:https://www.qianduange.cn//article/19035.html
标签
评论
还可以输入200
共0条数据,当前/页
发布的文章

安装Nodejs后,npm无法使用

2024-11-30 11:11:38

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!