必知C++之json第三方库JsonCpp使用操作

1. JSON概述

​ JSON: JavaScript 对象表示法( JavaScript Object Notation) 。是一种轻量级的数据交换格式。 它基于ECMAScript的一个子集。许多编程语言都很容易找到JSON 解析器和 JSON 库。 JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。

2. 常用C/C++ JSON库

​ 常用的C&C++的JSON库有cJSON、json-c、JsonCpp等,腾讯员工开源的一个RapidJSON以高性能著称。

3. windows 下使用VS编译jsoncpp

  • 在windows下 将 jsoncpp-0.10.7.tar.gz解压缩

  • 进入到解压目录jsoncpp-0.10.7, 在进入到子目录makefiles\msvc2010

  • 使用vs打开项目文件jsoncpp.sln

  • 编译该项目, 生成库文件

  • 生成的静态库存储目录jsoncpp-0.10.7\makefiles\msvc2010\Debug

  • 生成的静态库文件: lib_json.lib

  • 使用的准备工作:

    • 将静态库lib_json.lib拿出备用
    • 将库对应的头文件拿出, 头文件目录jsoncpp-0.10.7\include\json

注意点:
1.注意vs中的代码生成中的运行库一定要改成多线程调式(/MTd)
2.不使用库文件也行,使用源文件也行,可以在项目目录下直接执行python amalgamate.py命令,会在dist目录下生成两个头文件和一个源文件json-forwards.hjson.hjsoncpp.cpp。因为jsoncpp源码就四五千行,直接放在jsconcpp.cpp中和工程中其他代码一起编译也比较方便。

4.linux下的安装和部署

  • 准备安装包

    • jsoncpp-0.10.7.tar.gz
    • scons-3.0.5.zip
  • 解压缩

    $ tar zxvf jsoncpp-0.10.7.tar.gz
    $ unzip scons-3.0.5.zip
    
  • 安装scons -> 进入 scons-3.0.5.zip 的解压目录

    # 要使用管理员权限执行该命令
    $ python setup.py install 
    
  • 安装 jsoncpp -> 进入 jsoncpp-0.10.7.tar.gz 的解压目录

    $ scons platform=linux-gcc 
    # 将生成的动态库/静态库拷贝到系统的库目录中, 需要管理员权限
    $ cp libs/linux-gcc-***/* /lib
    # 拷贝json的头文件到系统目录中, 需要管理员权限
    $ cp include/json/ /usr/include/ -r
    # 创建动态库的链接文件, 需要管理员权限
    ln -s /lib/libjson_linux-gcc-xxx_libmt.so /lib/libjson.so
    # 更新, 这样才能搜索到动态库 libjson.so。需要管理员权限
    $ ldconfig	# ubuntu需需要加sudo
    # 测试
    $ ./bin/linux-gcc-***/test_lib_json 
    Testing ValueTest/checkNormalizeFloatingPointStr: OK
    Testing ValueTest/memberCount: OK
    Testing ValueTest/objects: OK
    Testing ValueTest/arrays: OK
    ..................
    Testing BuilderTest/settings: OK
    Testing IteratorTest/distance: OK
    Testing IteratorTest/names: OK
    Testing IteratorTest/indexes: OK
    All 53 tests passed
    
  • 编译 c++ 测试文件: json-test.cpp

    $ g++ json-test.cpp -ljson -o json
    

5. jsoncpp类的使用

/*
	三个类:
		Value, Reader, FastWriter
		
	Value类:
		- 将json支持的数据类型进行了包装, 最终得到一种类型 -> Value类型
			- 整形, 浮点型, 布尔类型, 字符串, json数组, json对象
		- 判断Value对象中的原始数据类型
		- 类型转换功能, 将Value对象转换成功原始数据
		- 给对象/数组添加元素
		
	Reader类: 反序列化, 将json字符串 解析成 Value 类型 
	FastWriter类: 将Value对象中的数据序列化为字符串
*/
// 如何使用Jsoncpp处理json数据
/*
	需要在内存中将json数组组织起来 -> 序列化为字符串
	1. 创建一个Value对象, 将数据添加到Value对象中
	2. 将Value对象序列化 -> 字符串 , 使用 FastWriter类
	3. 将字符串写入到文件中
*/

/*
	磁盘有一个json文件 (有一个josn字符串) -> 将字符串数据反序列化到到内存中
	1. 打开磁盘文件将json字符串读出
	2. 将字符串数据解析到 Value 中, 使用 Reader类
	3. 通过Value对象将Value中的数据依次读出
*/
/* 测试数据 */
[12, 12.34, true, "tom", ["jack", "ace", "robin"], {"sex":"man", "girlfriend":"lucy"}]

5.1 Value类

枚举类型 说明 翻译
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& operator=(Value other);
    
    // 因为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);
    
  • 检测保存的数据类型

    // 检测保存的数据类型
    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;
    
  • 基础数据类型访问并转换

    const char* asCString() const;
    JSONCPP_STRING asString() const;
    Int asInt() const;
    UInt asUInt() const;
    Int64 asInt64() const;
    UInt64 asUInt64() const;
    LargestInt asLargestInt() const;
    LargestUInt asLargestUInt() const;
    float asFloat() const;
    double asDouble() const;
    bool asBool() const;
    
  • 对json数组的操作

    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;
    const_iterator begin() const;
    const_iterator end() const;
    iterator begin();
    iterator end();
    
  • 对json对象的操作

    // 联想stl中的map
    obj["hello"] = "world";
    obj["hello"];
    
    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 char* begin, const char* end, 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 Members;
    Members getMemberNames() const;
    
  • 将Value对象数据序列化为string

    // 序列化得到的字符串有样式 -> 带换行 -> 方便阅读
    // 写配置文件的时候
    std::string toStyledString() const;
    
  • 数组追加元素

     Value& append(const Value& value);
    

5.2 Reader 类

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    -> wo
// read的文件流   -> ifstream	 -> ri
// 假设要解析的json数据在磁盘文件中
// is流对象指向一个磁盘文件, 读操作
bool Json::Reader::parse(std::istream& is, Value& root, bool collectComments = true);

5.3 FastWriter 类

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

6.这里实例介绍使用C++的json第三方库JsonCpp

主要介绍jsoncpp的新版本API操作,旧版的放在后面可以不看。

  • 新版API
//写操作
void NewApiFastWriter(){
	//生成Json
	Value root, mail, subArray;
	root["Name"] = "dxs4396";
	root["age"] = 20;
	mail["mail1"] = "[email protected]";
	mail["mail2"] = "[email protected]";
	mail["mail3"] = "[email protected]";
	root["mail"] = mail; 
	subArray.append(100);
	subArray.append(true);
	root["Array"] = subArray;
#if 0     
	//无样式版本获得字符串
	//方便进行数据的网络传输
	FastWriter writer;
	string json = writer.write(root);
#else     
	//有样式版本获得字符串
	//写配置文件时候方便阅读
	string json = root.toStyledString();
#endif
	ofstream ofs("newtest.json");
	if (ofs.is_open()) {
		ofs << json;
		ofs.close();
	}
	else {
		cout << "ofstream file failed\n";
	}
}
//字符串中读操作
void NewApiReader() {
	//Reader类解析json字符串
	Reader reader;
	Value root;
	const char* jsonstr = R"({"Name":"Joker000","age":21})";
	if (!reader.parse(jsonstr, jsonstr + strlen(jsonstr), root)) {
		cout << "json parse failed\n";
		return;
	}
	string name = root["Name"].asString();
	int age = root["age"].asInt();
	cout << "name=" << name << " " << "age=" << age << endl;
}
//json文件中读取操作
void newApiFileReader() {
	//Reader类解析磁盘json文件
	Value root;
	Reader reader;
	ifstream ifs("newtest.json");

	if (!reader.parse(ifs, root)) {
		cout << "failed\n";
	}
	else {
		cout << "success\n";
	}

	if (root.isArray()) {
		cout << "这是一个数组" << endl;
		//根据写操作中生成的json文件,不存在的省略即可。
	}
	else {
		cout << "这是一个对象" << endl;
		//按照json格式解析
		//遍历对象
		Value::Members keys = root.getMemberNames();
		for (int i = 0; i < keys.size(); ++i) {
			if (root[keys[i]].isArray()) {
				Value subVal = root[keys[i]];
				for (int j = 0; j < subVal.size(); ++j) {
					
					if (subVal[j].isInt()) {
						cout <
  • 旧版API(可忽略,用新版即可)
//流中读操作
int readFromStream() {
	Value root;
	ifstream ifs;
	ifs.open("test.json");
	CharReaderBuilder builder;
	builder["collectComments"] = true;
	string errs;
	if (!parseFromStream(builder, ifs, &root, &errs)) {
		cout << errs << endl;
		return EXIT_FAILURE;
	}
	cout << root << endl;
	return EXIT_SUCCESS;
}
//字符串中读操作
int ReadFromString() {
    //这个R"()"这个时C++新特性,可以不用写转义字符。
	const string rawJson = R"({"Age":20,"Name":"Joker"})";
	const auto rawJsonLenghth = static_cast(rawJson.length());
	constexpr bool shouldUserOldWay = false;
	string err;
	Value root;
	if (shouldUserOldWay) {
		Reader reader;
		reader.parse(rawJson, root);
	}
	else {
		CharReaderBuilder builder;
		const unique_ptr reader(builder.newCharReader());
		if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLenghth, &root, &err)) {
			cout << "error" << endl;
			return EXIT_FAILURE;
		}
	}
	const string name = root["Name"].asString();
	const int age = root["Age"].asInt();

	cout << "name:" << name<<"age:" <
//写入流中操作
int StreamWrite() {
	Value root;
	StreamWriterBuilder builder;
	const unique_ptr writer(builder.newStreamWriter());
	root["Name"] = "Joker";
	root["Age"] = 20;
	writer->write(root, &cout);
	return EXIT_SUCCESS;
}
//写如字符串中操作
int StringWrite() {
	Value root;
	Value data;
	constexpr bool shouldUseOldWay = false;
	root["name"] = "Joker";
	data["age"] = 20;
	root["data"] = data;
	if (shouldUseOldWay) {
		FastWriter writer;
		const string json_file = writer.write(root);
		cout << json_file << endl;
	}
	else {
		StreamWriterBuilder builder;
		const string json_file = writeString(builder, root);
		cout << json_file << endl;
	}
	return EXIT_SUCCESS;
}

你可能感兴趣的:(Json)