json文件是比较轻量级的文件,格式简单,使用方便。用来存放信息相比其他方式有自己得天独厚的优势。
今天给大家分享的是如何利用C++来操作json文件。
如果你知道如何使用jsoncpp类库,可以不用看附录,如果第一次使用,请先到最后,将环境配置好,再进行操作。
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
常用存储数据的方式有很多,比如利用txt文件,xml文件,word文件,Excel文件,如果我们要求比较高,还可以使用数据库文件(MySQL
/SQL Server
/Oracle
)。
程序中所有函数的调用我都写在最后的Main.cpp中,下面出现的声明、定义都是OperationJson.h与OperationJson.cpp中的内容的拆分版本。
解析之前,我们先定义一个简单的字符串(中间串),替代json格式的解析,如下:
/* Json格式 */
{
"name":"Cain",
"age":23,
"sex":"man"
}
/* 字符串格式 */
const char* str = "{\
\"name\":\"Cain\",\
\"age\":23,\
\"sex\":\"man\"\
}";
字符串格式解析:(大佬可以自行跳过,新手我说明一下)
"{\
:此处的\
意思是下一行接着这一行开始,并没有结束。\"name\”
:此处的\"
,代表字符串的转义,C语言基础,忘记了可以回顾下。\"age\":23
此处这么写,他就是一个in类型,待会儿就会用asIng()
,解析,内部也是如此,如果你是以\"age\":\"23\"
“”
,使用asString()
进行解析,而你要的是asInt()
,则会出现断言错误,因为jsoncpp中错误的处理方式都是断言。这里是我踩的坑,我说明一下,分享给大家,后面的例子中,涉及我不会再重复提出。Kernel Code:
#include
//声明
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;
}
还是先定义一个字符串(复杂一点),如下:
//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。
读写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();
}
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;
}
}
#include
#include
#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.如果文件存在,写入过程不会覆盖文件中原有数据,而是将新数据写在原有数据后面。
JsonCpp是一个基于C++语言的开源库,用于C++程序的Json数据的读写操作。
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/
我使用的是第三个链接下载的库包,下面我配置也是如此,以第三个为例,核心步骤都一样,不用担心下载地址的不同而无法使用。
配置到此处,项目里就可以使用Jsoncpp库了。
关于iostream.h
的使用,就是写文件的时候如果没有自己手动创建文件,按照上面的代码是无法创建的,必须在ofstream os(文件路径);
,这样就可以创建了,这里说明一下,读文件是不需要的,只需要给对路径文件就可以了。
jsoncpp配置所连接的github地址参考了下面文章中的引用:
https://www.cnblogs.com/esCharacter/p/7657676.html
版权声明:创作不易,转载请注明出处!