前言

json文件是比较轻量级的文件,格式简单,使用方便。用来存放信息相比其他方式有自己得天独厚的优势。

今天给大家分享的是如何利用C++来操作json文件。

如果你知道如何使用jsoncpp类库,可以不用看附录,如果第一次使用,请先到最后,将环境配置好,再进行操作。

01、json文件介绍

1.1、json简介

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率

1.2、json优势

常用存储数据的方式有很多,比如利用txt文件,xml文件,word文件,Excel文件,如果我们要求比较高,还可以使用数据库文件(MySQL/SQL Server/Oracle)。

  1. 相对于txt,word来说,json格式更加明确,获取重要信息非常方便。
  2. 相对于xml来说,json格式更加简洁,存储同样的文件,花费的内存更小。
  3. 相对于Excel来说,json更适合存储字符类文件。Excel相当于比较简单的数据库了。
  4. 相对于数据库来说,json更加方便,数据库我们还需要做一些设置,安装一些软件。json可以直接使用。

02、C++ 操作 jsoncpp(读、写、解析)

程序中所有函数的调用我都写在最后的Main.cpp中,下面出现的声明、定义都是OperationJson.h与OperationJson.cpp中的内容的拆分版本。

2.1、解析(nor)

解析之前,我们先定义一个简单的字符串(中间串),替代json格式的解析,如下:

/* Json格式 */
{
	"name":"Cain",
	"age":23,
	"sex":"man"
}
/* 字符串格式 */
const char* str = "{\
					\"name\":\"Cain\",\
					\"age\":23,\
					\"sex\":\"man\"\
					}";

字符串格式解析:(大佬可以自行跳过,新手我说明一下)

  1. "{\:此处的\意思是下一行接着这一行开始,并没有结束。
  2. \"name\”:此处的\",代表字符串的转义,C语言基础,忘记了可以回顾下。
  3. json中的所有值格式都是通过首、尾来标识的,什么意思呢,就是说,如果,你在\"age\":23此处这么写,他就是一个in类型,待会儿就会用asIng(),解析,内部也是如此,如果你是以\"age\":\"23\"
    这一种方式写的,内部识别首尾为“”,使用asString()进行解析,而你要的是asInt(),则会出现断言错误,因为jsoncpp中错误的处理方式都是断言。这里是我踩的坑,我说明一下,分享给大家,后面的例子中,涉及我不会再重复提出。

Kernel Code:

#include <string>

//声明
void AnalysisJsonString(string strJsonText);

//定义  (实际我是以类的形式对这三种写法写的代码,这只是我拆分出来方便大家看)
void OperJson::AnalysisJsonString(string strJsonText)
{
	string name,sex;
	int age;
	
	Json::Reader reader;
	Json::Value value;

	//从字符串中读取数据
	if(reader.parse(strJsonText,value))
	{
		name = value["name"].asString();
		age = value["age"].asInt();
		sex = value["sex"].asString();
	}

	//输出格式大家自定义就好了,我这么写完全是为了输出好看
	cout << "{ " << endl;
	cout << "   " << "\"name\":" << " \" " << name << " \" " <<endl;
	cout << "   " << "\"age\":" << age<<endl;
	cout << "   " << "\"sex\":" << " \" " << sex<< " \" " <<endl;
	cout << "} " << endl;
}

Run Image:
在这里插入图片描述

2.2、解析(pro)

还是先定义一个字符串(复杂一点),如下:

//Json格式
{
	"name":"Cain",
	"major":
	[
	{ "computer" : "C"},
	{ "computer" : "C++"},
	{ "computer" : "Python"},
	{ "computer" : "Go"}
	]
}

//字符串格式
const char* buf = "{\
					\"name\":\"Cain\",\
					\"major"\:[{\
					\"computer\":\"C\"},\
					\"computer\":\"C++\"},\
					\"computer\":\"Python\"},\
					\"computer\":\"Go\"}\
					]}";

字符串解析(略)。

Kernel Code:

//声明
void AnalysisJsonStringPro(string strJsonText);

//定义
void OperJson::AnalysisJsonStringPro(string strJsonText)
{
	string name;
	string major;
	vector<string> vec;  //包含vector头文件
	
	Json::Reader reader;
	Json::Value value;
	Json::Value root;
	
	if(reader.parse(strJsonText,root))
	{
		name = root["name"].asString();
		value = root["major"];
		cout << "name: " << name << endl;
		
		for(int i = 0; i < root["major"].size(); i++)
		{
			major = value[i]["computer"].asString();
			vec.push_back(major);
		}
	}
	//区间迭代(C++ 11)
	for(string buf : vec)
	{
		cout << "major: " << buf << endl;
	}
}

关于区间迭代,感兴趣可以查看我以前写的一篇STL博客 【STL】标准容器-vector

Run Image:
在这里插入图片描述

2.3、写Json文件

读写Json文件我就直接上代码+测试图,感兴趣,大家可以拿去自己测试,程序肯定是OK的。

Kernel Code:

//声明
void WriteFileJson(string filePath);

//定义
void OperJson::WriteFileJson(string filePath)
{
	//写入下列指定内容
	const char* str = "{\
						\"name\":\"Cain\",\
						\"sex\":\"man\",\
						\"age\":23,\
						\"hobby\":[\"Run\",\"Sing\",\"Dance\"],\
						\"major\":[\
						{\"subject1\":\"C++\"},\
						{\"subject2\":\"Jave\"},\
						{\"subject3\":\"Go\"}]\
						}";

	Json::Value root;
	root["name"] = Json::Value("Cain");
	root["sex"] = Json::Value("man");
	root["age"] = Json::Value(23);
	
	//数组形式
	root["hobby"].append("Run");
	root["hobby"].append("Sing");
	root["hobby"].append("Dance");
	
	Json::Value Sub;
	//子节点属性
	Sub["subject1"] = Json::Value("C++");
	Sub["subject2"] = Json::Value("Java");
	Sub["subject3"] = Json::Value("Go");

	//将子节点内容挂到父节点(root)上
	root["major"] = Json::Value(Sub);

	/* 测试内容:会在屏幕输出 */
	cout << "styledwriter: " << endl;
	Json::StyledWriter sw;
	cout << sw.write(root) << endl;

	//将内容输入到指定的文件
	ofstream os;
	os.open(filePath,ios::out || iios::app);
	if(!os.is_open())
	{
		cout << "Error: can not find or create the file which named " << filePath << endl;
	}
	else
	{
		cout << "successful: file write is success! " << endl;
	}

	os << sw.write(root);
	os.close();
}

Run Image:
在这里插入图片描述
在这里插入图片描述

2.4、读Json文件

Kernel Code:

//声明
void ReadFileJson(string filePath);

//定义
void OperJson::ReadFileJson(string filePath)
{
	Json::Reader reader;
	Json::Value root;
	
	//读取文件中的数据
	ifstream in;
	in.open(filePath,ios::in || ios:: binary);
	if(!in.is_open())
	{
		cout << "Error: open file is failed! " << endl;
	}
	else
	{
		cout << "Successful: file read is success! " << endl;
	}
	
	Json::StyledWriter sw;

	if(reader.parse(in,root))
	{
		//读取节点信息
		string name = root["name"].asString();
		int age = root["age"].asInt();
		string sex = root["sex"].asString();
		
		for(int i = 0; i < root["hobby"].size(); i++)
		{
			string str = root["hobby"][i].asString();
		}

		Json::Value tmp;
		tmp = root["major"];

		sw write(root);
		cout << sw.write(root) << endl;
	}
	else
	{
		cout << "Error: parse is error! " << endl;
	}
}

Run Image:
在这里插入图片描述

2.5、Main.cpp
#include <iostream>
#include <string>
#include "OperationJson.h"

using namespace std;

/* 定义两个宏,使读写json文件区分开来,当然也可以只用一个,读写都用一个,最简单 */
#define READ_JSONFILE_PATH "C:\\Users\\M\\Desktop\\read.json"
#define WRITE_JSONFILE_PATH "C:\\Users\\M\\Desktop\\write.json"

int maiin(int argc,char* argv[])
{
	const char* str = "{\
					\"name\":\"Cain\",\
					\"age\":23,\
					\"sex\":\"man\"\
					}";
					
	const char* buf = "{\
					\"name\":\"Cain\",\
					\"major"\:[{\
					\"computer\":\"C\"},\
					\"computer\":\"C++\"},\
					\"computer\":\"Python\"},\
					\"computer\":\"Go\"}\
					]}";

	OperJson json;

	//简单解析Json(字符串形式)
	json.AnalysisJsonString(str);
	//升级版解析Json(字符串形式)
	json.AnalysisJsonString(buf);
	//写Json文件
	json.WriteFileJson(WRITE_JSONFILE_PATH);
	//读Json文件
	json.ReadFileJson(READ_JSONFILE_PATH);

	system("pause");
	return 0;
}

Ps:如果按照我上面这样写两个宏,那么json文件要么是从外部创建,要么就是先写再重命名。因为实际我们使用json文件的时候都不是同名的,当然测试使用同名肯定是更简单,大家自行决定。
上面涉及到iostream.h头文件中的读写方法,这是C++中的方法,同C原理相同,可以网上了解一下。
要注意的是:
1.如果要写入的文件不存在,会自动创建该文件;
2.如果文件存在,写入过程不会覆盖文件中原有数据,而是将新数据写在原有数据后面。

03、Jsoncpp库配置从0到1

JsonCpp是一个基于C++语言的开源库,用于C++程序的Json数据的读写操作。

3.1、Jsoncpp库下载

Jsoncpp库github地址:https://github.com/open-source-parsers/jsoncpp
Jsoncpp文档地址:http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html
jsoncpp官网库地址:https://sourceforge.net/projects/jsoncpp/

我使用的是第三个链接下载的库包,下面我配置也是如此,以第三个为例,核心步骤都一样,不用担心下载地址的不同而无法使用。

3.2、配置步骤
  • 解压并转移
    首先将库解压,将下面的两个文件夹复制到你创建的项目下面,如下图:
    在这里插入图片描述
    在这里插入图片描述

  • 项目配置
    首先进入你的VS项目,依次点击工具栏上的项目——>属性,然后按照下图步骤操作:

在这里插入图片描述

  • Jsoncpp头文件使用

    将刚才的include文件夹下的所有文件和src下的json文件夹下的所有文件一起拷贝到项目目录下的新建筛选项(直接在VS界面添加、新建筛选项即可)下,如下图在这里插入图片描述
    在这里插入图片描述

配置到此处,项目里就可以使用Jsoncpp库了。

04、附录

关于iostream.h的使用,就是写文件的时候如果没有自己手动创建文件,按照上面的代码是无法创建的,必须在ofstream os(文件路径);,这样就可以创建了,这里说明一下,读文件是不需要的,只需要给对路径文件就可以了。

jsoncpp配置所连接的github地址参考了下面文章中的引用:
https://www.cnblogs.com/esCharacter/p/7657676.html

版权声明:创作不易,转载请注明出处!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐