C++,rapidjson读写json文件操作


第一次写这种博文,因为工作需要,学习了一下写入数据进入json文件,并读取的操作,这里简单记录一下相关内容的用法。
一、C++的文件操作
C++对文件比较经典的操作是时使用fopen,fclose等相关的函数打开,创建或者是关闭一个文件,不过我在我的 操作中使用的是文件流的方式来实现对json文件的读写,所以我大概说一下这方面的操作。
1、头文件
头文件中有关文件操作的是<fstream>头文件,使用文件流操作的时候需要调用这个头文件
2、函数
(1)文件写入操作
首先,如果是向文件写入才最需要使用std::ofstream来顶一个对象,具体操作:
std::ofstream outfile(fliename);
filename可以自己定义,比如说example.txt,example.json这类的
在C++中,文件操作是通过标准库中的iostream头文件和fstream类来实现的。利用fstream类可以方便地读取和写入文件。使用上述方式打开的文件是std::out类型,这种方式是会打开一个特定的文件,而不会自己创建一个文件。
有以下3种模式:
- std::ios::ate:以追加模式打开文件,并将文件指针移动到文件的末尾.
- std::ios::app:以追加模式打开文件,并将文件指针移动到文件的末尾。
- std::ios::trunc:以写入模式打开文件,并截断文件的长度为零。
其中若文件一开始不存在,使用std::app模式才会自动创建一个文件,其他两个模式则不会。
具体来说,如果是用std::ofstream的对象打开并创建一个文件,具体的方法是:
std::ofstream outfile(fliename,std::ios::out|std::ios::app);
(2)文件读取操作
文件读取操作调用的是std::ifstream,具体方法:
std::ifstream infile("example.txt",std::ios::in);
读取操作就不需要时候用上面的3个类型了,如果文件一开始不存在是打不开文件的,可以使用is_open函数来检查文件是否打开,当然也可以使用!inflle来判断文件是否已经打开。
(3)seekg,seekp,tellg,tellp
g相当于get,p相当于put
seekg:它是istream类对象的成员函数,用于设置输入流的读取位置。它接受一个参数,表示需要跳过的字节数,以及一个可选的参数,表示相对于哪个位置进行跳转,默认为文件开头位置(ios::beg)。
seekp:它是ostream类对象的成员函数,用于设置输出流的写入位置。它接受一个参数,表示需要跳过的字节数,以及一个可选的参数,表示相对于哪个位置进行跳转,默认为文件开头位置(ios::beg)。
tellg:它是istream类对象的成员函数,用于获取当前输入流的读取位置。它不接受任何参数,并返回一个streampos类型的值,表示当前读取位置的字节数。
tellp:它是ostream类对象的成员函数,用于获取当前输出流的写入位置。它不接受任何参数,并返回一个streampos类型的值,表示当前写入位置的字节数。
另外里面有一些有关偏移量的基本位置的标志,比如说
std::ios::beg:表示文件的起始位置,
std::ios::cur: 表示指针小在直销的位置,
std::ios::end:表示文件结束的位置,
比如说使用seekp函数,seekp(10,std::ios::beg),表示的是将写入的指针移到距离起始位置10的地方,seekp(-10,std::ios::end),表示的是将写入的指针移到距离文件结束还有10的位置。
(4)peek函数
在C++文件流操作中,peek()函数用于查看文件流中下一个字符而不会移动文件位置指针。该函数返回下一个字符的ASCII码值,如果文件结束或出现I/O错误则返回EOF。
(5)文件流的读写
要使用fstream类进行文件操作,需要先打开要读取或写入的文件。可以使用ofstream类来打开一个输出文件流,使用ifstream类打开一个输入文件流,或者使用fstream类打开一个既可以输入也可以输出的文件流。
使用fstream类打开时,可以写成std::fstream fs("example.txt",std::ios::in|std::ios::out);
在打开文件后,可以使用iostream中定义的输入/输出运算符(<< 和 >>)来读写文件中的数据。此外,也可以使用fstream类中提供的read()和write()函数读写二进制文件,或者使用getline()函数逐行读取文本文件中的内容。
最后,在完成对文件的操作后,需要关闭文件。可以使用close()函数来关闭fstream对象。
(6)删除文件
删除文件使用std::remove(filename)就可以了,里面的filename可以指定相对路径也可以是绝对路径。
二、使用rapidjson库读写json文件
我之前本身使用jsoncpp这个库写的json文件,但是后来发现我们的项目中有rapidjson库,所以后来又改成rapidjson写json文件了,所以这里也不写rapidjson库该怎么安装了,因为我也不会,安装jsoncpp库倒是成功了,但跟这里没关系就不提了。
rapidjson是一个C++的JSON解析库,可以方便地读取和写入JSON格式的文件。
包含头文件:
首先需要包含rapidjson的头文件,我使用了 "rapidjson/document.h","rapidjson/writer.h",""rapidjson/stringbuffer.h".
打开文件:
如上面的文件操作所示,从上面的文件操作就可以打开一个文件或者关闭一个文件。
写入JSON数据:
因为我需要持续的向文件中写入,所以我在调用的使用是这样写的:
std::ofstream fs("example.json", std::ios::out|std::ios::app);
这样写主要是第一是文件不存在的时候创建文件,第二是每次向文件中写入内容时还可以保留之前的内容, 其它都是会将之前的内容全部覆盖掉的。但是使用这个app模式,使用seekp调整写入指针是无法将之前的内 容覆盖的,比如说我当初想写一个seekp(-1,std::ios::end),想将文件的最后一个字符覆盖掉,但是这样实现得 不到想要的结果,最后一个字符还是保留的,所以这一点要注意。
这些内容准备好之后,就开始进行rapidjson的操作。我的情况是要写入一个类型的对象,对象中包括int类型和strng类型。
首先创建一个document对象,rapidjson::Document 是一个类模板,用于表示 JSON 文档的内存模型。具体来说,它是一个通用的树状结构,可以容纳任意类型的 JSON 值,包括数字、字符串、布尔值、空值、数组和对象等。该类提供了一组 API,用于从字符串或流中解析 JSON 数据,并在内存中构建相应的数据结构。
之后使用rapidjson::value来定义一个 数据,
rapidjson::Value new_object(kObjectType),
kObjectType的作用是将这个json数据标为一个对象类型。之后向这个对象中添加对象中的数据,
new_object.AddMember("a", request.a, doc.GetAllocator());
其中a表示对象中的一个成员数据,doc.GetAllocator() 函数返回一个指向文档的内存分配器的指针。这个内存分配器用于在解析 JSON 数据时动态分配和释放内存,并且是由 RapidJSON 自动管理的。因此,对于大多数情况下,我们不需要手动对内存进行分配或释放,而是可以让 RapidJSON 自动处理这些细节。
当对象中的内容写好之后,就开始向文件中写内容了:
rapidjson::StringBuffer buffer;
rapidjson::Writer<StringBuffer> writer(buffer);
new_object.Accept(writer);
std::string new_json_str = buffer.GetString();
代码处理程序如上:
首先使用rapidjson::stringbuffer类定义一个buffer,这是用来存储obj序列化之后的内容的。
之后创建一个 rapidjson::Writer 对象 writer,并将 buffer 作为参数传递给它。这里的 Writer 类是一个输出流,用于将 JSON 值写入到指定的输出缓冲区中。
将要序列化的 JSON 值 new_request 传递给 Accept() 成员函数,以便让 RapidJSON 知道需要序列化哪个值。
最终,我们可以通过调用 buffer.GetString() 函数获取序列化后的字符串。
这一切准备妥当之后,使用
outfile << new_json_str << std::endl;
使用文件流的形式将数据写入文件当中,之后别忘关闭文件。
读取JSON数据:
上面写入的操作是将对象一行一行存储的,所以在读取文件的时候就可以一行一行的读取文件的内容。
首先定义std::ifstream的对象打开example.json文件
std::ifstream infile("example.json");
使用getline函数,while (getline(infile, line))使用这个循环开始逐行读取文件
进入循环,首先创建rapidjson::document对象doc,调用:
doc.Parse(line.c_str());
来读取这一行的文件内容。
之后我们就可以新创建一个对象new_obj来获取文件中存储的内容
例如:new_obj.a = doc["a"].GetUint();
new_obj.b = doc["b"].GetString();
通过以上的操作就可以得到文件这一行的操作,最后关闭文件infile.close();
附录:
void object_write_to_json(Obj &object) {
std::string new_json_str;
rapidjson::Document doc;
doc.SetObject();
doc.AddMember("a", object.a, doc.GetAllocator());
doc.AddMember("b", object.b, doc.GetAllocator());
......
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
doc.Accept(writer);
new_json_str = buffer.GetString();
std::ofstream ofs("example.json", std::ios::out | std::ios::app);
if (!ofs.is_open()) {
ib::error() << "Failed to open file.";
return;
ofs << new_json_str << std::endl;
ofs.close();
void object_read_from_json(Obj &object) {
std::ifstream infile("example.json");
if (!infile.is_open()) {
ib::error() << "Failed to open file.";
return;
std::string line;
while (getline(infile, line)) {
rapidjson::Document doc;
doc.Parse(line.c_str());
if (doc.HasParseError() || !doc.IsObject()) {
ib::error() << "Failed to parse JSON object at line " << current_line;
return;