> 技术文档 > 【百度云盘项目实践(1)】:探索JSON与Bundle库的结合应用_json转换为bundle

【百度云盘项目实践(1)】:探索JSON与Bundle库的结合应用_json转换为bundle

 

hello !大家好呀! 欢迎大家来到我的Linux项目实战系列之《【百度云盘项目实践】:探索JSON与Bundle库的结合应用》,在这篇文章中,你将会学习到json数据格式,bundle库内对文件进行压缩与解压缩的过程,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!!

希望这篇文章能对你有所帮助,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!(注:这章对于高性能服务器的实现非常重要哟!!!)

03d6d5d7168e4ccb946ff0532d6eb8b9.gif           

目录

 一.Json

 1.1 json数据

JSON对象

JSON数组

JSON语法规则

JSON与C++的结合使用

1.2 Value实例

主要特性

常用操作

使用场景

1.3 json数据的序列化与反序列化

newStreamWriter()

newCharReader()

1.4 代码实例

二. bundle库 

文件压缩:

 文件解压:


 

 一.Json

 1.1 json数据

        

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于JavaScript编程语言的一个子集,但因其文本格式清晰、易于解析和生成,被广泛用于数据交换和存储。JSON格式支持的数据结构包括对象(Object)和数组(Array)。

JSON对象

JSON对象是一个无序的键:值对集合。每个键值对中的键是一个字符串,后跟一个冒号,然后是值。值可以是字符串、数值、布尔值、数组、对象或null。例如:

{ \"name\": \"张三\", \"age\": 30, \"isStudent\": false, \"courses\": [\"数学\", \"物理\", \"化学\"], \"address\": { \"city\": \"北京\", \"street\": \"长安街\" }}

在这个例子中,nameageisStudentcoursesaddress是键,它们对应的值分别是字符串、数值、布尔值、数组和另一个对象。

JSON数组

JSON数组是一个有序的值列表,可以通过索引访问。数组中的值可以是字符串、数值、布尔值、数组、对象或null。例如:

[ { \"name\": \"张三\", \"age\": 30 }, { \"name\": \"李四\", \"age\": 25 }]

这个例子中,数组包含两个对象,每个对象都有nameage属性。

JSON语法规则

  • 数据在键值对中
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组

JSON与C++的结合使用

在C++中,可以使用如nlohmann/json等库来解析和生成JSON数据。例如,使用这个库解析上述JSON对象:

#include #include using json = nlohmann::json;int main() { std::string jsonString = \"{\\\"name\\\": \\\"张三\\\", \\\"age\\\": 30}\"; json j = json::parse(jsonString); std::cout << \"姓名: \" << j[\"name\"].get() << std::endl; std::cout << \"年龄: \" << j[\"age\"].get() << std::endl; return 0;}

这段代码解析了一个包含姓名和年龄的JSON对象,并打印出这些信息。

JSON因其简洁和易用性,在Web应用、移动应用和许多其他场景中被广泛使用,特别是在数据交换和配置文件中。

1.2 Value实例

在JSONCpp库中,Json::Value实例是表示JSON数据结构的基本对象。它可以表示JSON中的各种数据类型,如对象(Object)、数组(Array)、字符串(String)、数值(Number)、布尔值(Boolean)和null。Json::Value实例是JSONCpp库的核心,用于创建、修改和访问JSON数据。

主要特性

  • 多态性:一个Json::Value实例可以表示不同的数据类型。
  • 动态性:可以在运行时改变Json::Value实例所表示的数据类型。
  • 易于使用:通过简单的API,可以方便地操作JSON数据。

常用操作

  • 创建和赋值
    Json::Value value;value[\"key\"] = \"value\"; // 创建一个键值对value[\"array\"].append(1); // 向数组中添加元素
  • 访问数据
    std::string str = value[\"key\"].asString();int num = value[\"array\"][0].asInt();
  • 检查数据类型
    if (value.isObject()) { // 处理对象}if (value.isArray()) { // 处理数组}
  • 遍历对象和数组
    // 遍历对象for (Json::Value::const_iterator it = value.begin(); it != value.end(); ++it) { std::string key = it.key().asString(); Json::Value keyValue = *it; // 处理键值对}// 遍历数组for (unsigned int i = 0; i < value.size(); ++i) { Json::Value arrayElement = value[i]; // 处理数组元素}

使用场景

  • 序列化:将C++数据结构转换为JSON字符串。
  • 反序列化:将JSON字符串解析回C++数据结构。
  • 数据交换:在不同系统或服务间交换数据。
  • 配置文件:读取和写入配置数据。

Json::Value实例是JSONCpp库的基础,通过它可以轻松地处理复杂的JSON数据结构。

 

1.3 json数据的序列化与反序列化

在C++中,序列化是指将数据结构(如对象、数组等)转换为JSON字符串的过程,而反序列化则是将JSON字符串解析回相应的数据结构。使用如nlohmann/json库可以方便地进行这些操作。

 

在JSONCpp库中,newStreamWriter()newCharReader()是用于JSON数据序列化和反序列化的重要函数。

newStreamWriter()

newStreamWriter()函数是Json::StreamWriterBuilder类的一个方法,用于创建一个Json::StreamWriter对象,该对象负责将Json::Value对象转换为JSON格式的字符串。

作用

  • 序列化:将C++中的Json::Value对象转换为JSON字符串。
  • 格式化:可以设置缩进、空格等格式化选项,使生成的JSON字符串更易于阅读。

使用方法

  1. 创建StreamWriterBuilder实例。
  2. 通过newStreamWriter()创建StreamWriter对象。
  3. 使用StreamWriterwrite()方法将Json::Value对象转换为字符串。

示例

Json::StreamWriterBuilder swb;std::unique_ptr sw(swb.newStreamWriter());stringstream ss;sw->write(root, &ss); // 将root序列化为JSON字符串,存储在ss中

newCharReader()

newCharReader()函数是Json::CharReaderBuilder类的一个方法,用于创建一个Json::CharReader对象,该对象负责将JSON字符串解析为Json::Value对象。

作用

  • 反序列化:将JSON字符串解析回C++中的Json::Value对象。
  • 错误处理:在解析过程中,如果遇到错误,可以提供错误信息。

使用方法

  1. 创建CharReaderBuilder实例。
  2. 通过newCharReader()创建CharReader对象。
  3. 使用CharReaderparse()方法将JSON字符串解析为Json::Value对象。

示例

Json::CharReaderBuilder cwb;unique_ptr cw(cwb.newCharReader());string err;bool ret = cw->parse(json_str.c_str(), json_str.c_str() + json_str.size(), &root2, &err);// 解析json_str到root2,如果失败,错误信息存储在err中

总结

newStreamWriter()newCharReader()是JSONCpp库中用于JSON数据序列化和反序列化的重要工具。newStreamWriter()用于创建一个可以将Json::Value对象转换为JSON字符串的StreamWriter对象,而newCharReader()用于创建一个可以将JSON字符串解析回Json::Value对象的CharReader对象。这些功能在处理JSON数据时非常关键,尤其是在需要与JSON格式数据进行交互的应用程序中。

1.4 代码实例

        这是一个典型的json数据序列号与反序列化的程序:

#include#include#include#include#includeusing namespace std;int main(){ const char * name = \"小明\"; int age = 18 ; float score[]= {77.5 , 88 ,93.6}; //创建一个Value实例 Json::Value root; //向Value实例中添加数据 root[\"姓名\"] = name; root[\"年龄\"] = age; root[\"成绩\"].append(score[0]); root[\"成绩\"].append(score[1]); root[\"成绩\"].append(score[2]); //创建一个StreamWriterBuilder实例 Json::StreamWriterBuilder swb ; std::unique_ptr sw(swb.newStreamWriter()); stringstream ss; //开始序列化,json序列化的字符串保存在ss中 sw->write(root , &ss); cout<<ss.str()<<endl; //反序列化过程 string json_str = ss.str();//获取json字符串 Json::Value root2; Json::CharReaderBuilder cwb; unique_ptr cw(cwb.newCharReader()); string err; //反序列化过程 bool ret = cw->parse(json_str.c_str() ,json_str.c_str() + json_str.size() , &root2 , &err); if(ret == false){ cout<<\"反序列化失败\"<< err <<endl; } // 输出反序列化后的数据 cout << \"姓名: \" << root2[\"姓名\"].asCString() << endl; cout << \"年龄: \" << root2[\"年龄\"].asInt() << endl; cout << \"成绩: \"; for (int i = 0; i < root2[\"成绩\"].size(); ++i) { cout << root2[\"成绩\"][i].asFloat() << \" \"; } cout << endl; return 0;}

 

二. bundle库 

        bundle库中是有关于文件压缩与解压缩的23中方法的一个库,我们在云盘项目中,当用户进行文件的上传与下载时,我们需要对文件进行压缩与解压缩的过程,此时我们可以直接调用bundle库中的对应API来对我们文件进行处理,由于这个库内容比较简单,我就展示一个简单的示例使用程序:

文件压缩:

这是压缩程序:当我们选择一个文件,可以按照我们指定的方式进行压缩为指定的文件。

#include#include#include#include\"bundle.h\"using namespace std;int main(int argc , char * argv[]){ std::cout<<\"argv[1]是原始文件名字\\n\" ; std ::cout<<\"argv[2]是压缩包名字\\n\"; if(argc < 3) return -1; std::string ifilename = argv[1]; std::string ofilename = argv[2]; std::ifstream ifs;//创建文件输入输出流 ifs.open(ifilename , std::ios::binary);//二进制打开文件 ifs.seekg(0,std::ios::end);//跳转到文件末尾 size_t fsize = ifs.tellg();//获取文件大小 ifs.seekg(0,std::ios::beg);//跳转到文件起始 std::string body; body.resize(fsize);//调整body大小为文件大小 ifs.read(&body[0],fsize);//读取文件所有数据到body std::string packed = bundle::pack(bundle::LZIP,body);//以Lzip格式压缩文件 std::ofstream ofs; ofs.open(ofilename, std::ios::binary);//打开压缩包 ofs.write(&packed[0],packed.size());//将压缩后的文件写入压缩包文件 ifs.close(); ofs.close(); return 0;}

这是我们压缩前httplib.h文件的大小,为321K。

 

我们进行压缩为.lz压缩包后: 明显我们的压缩包大小变成了49k,压缩比例还是很客观的。

 

 

 文件解压:

这里给一个文件解压到另外一个文件的程序:

#include#include#include#include\"bundle.h\"using namespace std;int main(int argc , char *argv[]){ if(argc <3){ cout <<\"argv[1]是压缩包名称\"<<endl; cout<<\"argv[2]是解压后的文件名称\"<<endl; return -1; } string ifilename = argv[1] ;//获取压缩包名称 string ofilename = argv[2];//获取解压后的文件名 ifstream ifs; ifs.open(ifilename ,std::ios::binary);//打开压缩包 ifs.seekg(0 , ios::end);//跳转到文件末尾 size_t fsize = ifs.tellg();//获取文件大小 ifs.seekg(0 ,ios::beg);//跳转到起始位置 std::string body; body.resize(fsize); ifs.read(&body[0],fsize);//将压缩包数据传入body ifs.close(); string unpacked = bundle::unpack(body);//进行解压缩,数据存入unpacked ofstream ofs ; ofs.open(ofilename, std::ios::binary); ofs.write(&unpacked[0] , unpacked.size());//数据写入解压文件 ofs.close(); return 0;}

这个程序的实机演示和上面差不多,大家可以自己试试,这里不过多演示了。

       好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多注释,如果大家还有不懂得,可以评论区或者私信我都可以哦4d7d9707063b4d9c90ac2bca034b5705.png!! 感谢大家的阅读,我还会持续创造网络编程相

关内容的,记得点点小爱心和关注哟!

2cd0d6ee4ef84605933ed7c04d71cfef.jpeg