51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

jsoncpp的编译和使用

在前面的文章中为大家介绍了C语言中如何使用cjson处理json数据,接下来讲一下json在C++中的处理,这里给大家介绍一个开源的库jsoncpp

  1. 下载和编译 {#1-下载和编译} ===================

1.1 下载 {#1-1-下载}

下载 jsoncpp {#下载-jsoncpp}

Jsoncpp是个跨平台的C++开源库,提供的类为我们提供了很便捷的操作,而且使用的人也很多。在使用之前我们首先要从github仓库下载源码,地址如下:

|-----------|--------------------------------------------------------| | 1 | https://github.com/open-source-parsers/jsoncpp |

下载 cmake 工具 {#下载-cmake-工具}

由于C++程序猿都是基于VS进行项目开发,下载的源码我们一般不会直接使用,而且将其编译成相应的库文件(动态库或者静态库),这样不论是从使用或者部署的角度来说,操作起来都会更方便一些。

但是,从github下载的源码不能直接通过VS打开,编译就更谈不上了。它提供的默认编译方式是cmake。我们可以通过使用cmake工具将下载的jsoncpp源码生成一个VS项目,这样就可以通过VS编译出需要的库文件了。

CMake工具的官方下载地址如下:

|-----------|-------------------------------------| | 1 | https://cmake.org/download/ |

在这最新的安装包,根据向导完成安装即可。

1.2 生成VS项目 {#1-2-生成VS项目}

打开安装好的CMake工具

需要在工具中指定本地的jsoncpp路径(git clone 之后就会得到这个目录),这是我本地的目录:

第二个需要指定的是一个文件存储路径(生成的VS项目会保存到这个目录下),保证这是一个本地的有效目录即可。

设置好之后进行配置,点击Configure按钮

此处需要设置一下,VS的版本以及生成器的平台位数,不填默认就是64位。

配置完成,开始生成VS项目。

打开在CMake工具中指定的生成目录,我这里是D:\output-project,基于项目文件jsoncpp.sln打开这个VS项目。

1.3 编译 {#1-3-编译}

基于生成的项目文件打开VS项目之后,可以看到里边有很多子项目

我们只需要编译上图标记的那一个就可以了,编译成功之后就可以得到我们需要的库文件了。

通过输出的日志信息,就能找到我们想要的动态库了,把这两个文件收集起来备用。

  1. jsoncpp 的使用 {#2-jsoncpp-的使用} ===============================

jsoncpp库中的类被定义到了一个Json命名空间中,建议在使用这个库的时候先声明这个命名空间:

|-----------|-------------------------------| | 1 | using namespace Json; |

使用jsoncpp库解析json格式的数据,我们只需要掌握三个类:

  1. Value 类:将json支持的数据类型进行了包装,最终得到一个Value类型
  2. FastWriter类:将Value对象中的数据序列化为字符串
  3. Reader类:反序列化, 将json字符串 解析成 Value 类型

2.1 Value类 {#2-1-Value类}

这个类可以看做是一个包装器,它可以封装Json支持的所有类型,这样我们在处理数据的时候就方便多了。

| 枚举类型 | 说明 | 翻译 | |--------------|-----------------------------------------------|-------------------| | nullValue | 'null' value | 不表示任何数据,空值 | | intValue | signed integer value | 表示有符号整数 | | uintValue | unsigned integer value | 表示无符号整数 | | realValue | double value | 表示浮点数 | | stringValue | UTF-8 string value | 表示utf8格式的字符串 | | booleanValue | bool value | 表示布尔数 | | arrayValue | array value (ordered list) | 表示数组,即JSON串中的[] | | objectValue | object value (collection of name/value pairs) | 表示键值对,即JSON串中的{} |

构造函数 {#构造函数}

Value类为我们提供了很多构造函数,通过构造函数来封装数据,最终得到一个统一的类型。

|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 | // 因为Json::Value已经实现了各种数据类型的构造函数 Value(ValueType type = nullValue); Value(Int value); Value(UInt value); Value(Int64 value); Value(UInt64 value); Value(double value); Value(const char* value); Value(const char* begin, const char* end); Value(bool value); Value(const Value& other); Value(Value&& other); |

检测保存的数据类型 {#检测保存的数据类型}

|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | // 检测保存的数据类型 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; |

将Value对象转换为实际类型 {#将Value对象转换为实际类型}

|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | Int asInt() const; UInt asUInt() const; Int64 asInt64() const; UInt64 asUInt64() const; LargestInt asLargestInt() const; LargestUInt asLargestUInt() const; JSONCPP_STRING asString() const; float asFloat() const; double asDouble() const; bool asBool() const; const char* asCString() const; |

对json数组的操作 {#对json数组的操作}

|---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ArrayIndex size() const; Value& operator[](ArrayIndex index); Value& operator[](int index); const Value& operator[](ArrayIndex index) const; const Value& operator[](int index) const; // 根据下标的index返回这个位置的value值 // 如果没找到这个index对应的value, 返回第二个参数defaultValue Value get(ArrayIndex index, const Value& defaultValue) const; Value& append(const Value& value); const_iterator begin() const; const_iterator end() const; iterator begin(); iterator end(); |

对json对象的操作 {#对json对象的操作}

|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Value& operator[](const char* key); const Value& operator[](const char* key) const; Value& operator[](const JSONCPP_STRING& key); const Value& operator[](const JSONCPP_STRING& key) const; Value& operator[](const StaticString& key); // 通过key, 得到value值 Value get(const char* key, const Value& defaultValue) const; Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; Value get(const CppTL::ConstString& key, const Value& defaultValue) const; // 得到对象中所有的键值 typedef std::vector<std::string> Members; Members getMemberNames() const; |

将Value对象数据序列化为string {#将Value对象数据序列化为string}

|---------------|----------------------------------------------------------------------------------------| | 1 2 3 | // 序列化得到的字符串有样式 -> 带换行 -> 方便阅读 // 写配置文件的时候 std::string toStyledString() const; |

2.2 FastWriter 类 {#2-2-FastWriter-类}

|---------------|----------------------------------------------------------------------------------------------| | 1 2 3 | // 将数据序列化 -> 单行 // 进行数据的网络传输 std::string Json::FastWriter::write(const Value& root); |

2.3 Reader 类 {#2-3-Reader-类}

|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | bool Json::Reader::parse(const std::string& document, Value& root, bool collectComments = true); 参数: - document: json格式字符串 - root: 传出参数, 存储了json字符串中解析出的数据 - collectComments: 是否保存json字符串中的注释信息 // 通过begindoc和enddoc指针定位一个json字符串 // 这个字符串可以是完成的json字符串, 也可以是部分json字符串 bool Json::Reader::parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments = true); // write的文件流 -> ofstream // read的文件流 -> ifstream // 假设要解析的json数据在磁盘文件中 // is流对象指向一个磁盘文件, 读操作 bool Json::Reader::parse(std::istream& is, Value& root, bool collectComments = true); |

  1. VS的配置 {#3-VS的配置} ===================

如果想要在VS中使用编译出的jsoncpp库,我们还需要做如下配置:

3.1 头文件 {#3-1-头文件}

在编码过程中需要在项目文件中包含从github下载得到的头文件,有两种处理方式:

  1. 将头文件放到项目目录下,直接被项目包含引用

  2. 将头文件放到一个本地固定目录,以后就不再动了,在VS项目属性中设置包含这个目录,我推荐这种

另外,在这个include目录中还有一个json子目录,所有的头文件都在这个子目录中,我们不要破坏这个目录结构:

在包含需要的头文件的时候,使用如下这种方式:

|-----------|--------------------------------| | 1 | #include <json/json.h> |

把本地的头文件目录在项目属性窗口中进行配置:

我这里头文件是放到了C盘jsoncpp目录中:

3.2 库文件 {#3-2-库文件}

我这里也是将生成的jsoncpp.libjsoncpp.dll放到了C盘(C:\jsoncpp\lib),在VS项目中需要指定这个库路径:

另外,还需要告诉VS需要加载的动态库是哪一个

此处指定的是动态库对应的lib文件,也就是jsoncpp.lib

配置完成之后,如果项目中使用了jsoncpp就可以编译通过了。在程序执行的时候,如果提示找不到jsoncpp的动态库,把 jsoncpp.dll 拷贝到可执行所在的目录下就可以解决这个问题了。

  1. 示例代码 {#3-示例代码} =================

比如:我们要将下面这个Json数组写入的一个文件中

|-------------------------|--------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | [ 12, 12.34, true, "tom", ["jack", "ace", "robin"], {"sex":"man", "girlfriend":"lucy"} ] |

|---------------------------|-----------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 | #include <json/json.h> #include <fstream> using namespace Json; int main() { writeJson(); readJson(); } |

3.1 写json文件 {#3-1-写json文件}

|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | void writeJson() { // 将最外层的数组看做一个Value // 最外层的Value对象创建 Value root; // Value有一个参数为int 行的构造函数 root.append(12); // 参数进行隐式类型转换 root.append(12.34); root.append(true); root.append("tom"); // 创建并初始化一个子数组 Value subArray; subArray.append("jack"); subArray.append("ace"); subArray.append("robin"); root.append(subArray); // 创建并初始化子对象 Value subObj; subObj["sex"] = "woman"; // 添加键值对 subObj["girlfriend"] = "lucy"; root.append(subObj); // 序列化 #if 1 // 有格式的字符串 string str = root.toStyledString(); #else FastWriter f; string str = f.write(root); #endif // 将序列化的字符串写磁盘文件 ofstream ofs("test.json"); ofs << str; ofs.close(); } |

3.2 读json文件 {#3-2-读json文件}

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | void readJson() { // 1. 将磁盘文件中的json字符串读到磁盘文件 ifstream ifs("test.json"); // 2. 反序列化 -> value对象 Value root; Reader r; r.parse(ifs, root); // 3. 从value对象中将数据依次读出 if (root.isArray()) { // 数组, 遍历数组 for (int i = 0; i < root.size(); ++i) { // 依次取出各个元素, 类型是value类型 Value item = root[i]; // 判断item中存储的数据的类型 if (item.isString()) { cout << item.asString() << ", "; } else if (item.isInt()) { cout << item.asInt() << ", "; } else if (item.isBool()) { cout << item.asBool() << ", "; } else if (item.isDouble()) { cout << item.asFloat() << ", "; } else if (item.isArray()) { for (int j = 0; j < item.size(); ++j) { cout << item[j].asString() << ", "; } } else if (item.isObject()) { // 对象 // 得到所有的key Value::Members keys = item.getMemberNames(); for (int k = 0; k < keys.size(); ++k) { cout << keys.at(k) << ":" << item[keys[k]] << ", "; } } } cout << endl; } } |

在上面读Json文件的这段代码中,对读出的每个Value类型的节点进行了类型判断,其实一般情况下是不需要做这样的判断的,因为我们在解析的时候是明确地知道该节点的类型的。

虽然Json这种格式无外乎数组和对象两种,但是需求不同我们设计的Json文件的组织方式也不同,一般都是特定的文件对应特定的解析函数,一个解析函数可以解析任何的Json文件这种设计思路是坚决不推荐的。

赞(0)
未经允许不得转载:工具盒子 » jsoncpp的编译和使用