主角介绍
JSON是一种轻量级的数据交换格式,它采用完全独立的语言文本格式,使用了类似c家族的风格。使得JSON易于人读写,同时也易于机器解析和生成。
竞争对手
JSON对标的一直都是XML,网上也有很多两者对比,其实都带有很多的主观性…
(因为我也做过一样的事😄)下面是我以前做过的一个两者对比,大家看看就行,勿放心上…
因为我那段时间一直用xml,所以一直暗示自己,哈哈哈哈哈哈哈哈。其实都用过之后,现在客观来说,两者差不多,可以肯定的一点是,xml读写的代码量很冗杂,但是文件比较适合人阅读。图片中最后那句总结,没毛病的,毕竟很多时候配置文件,需要直接在文件中更改。说一句认真的,希望大家不要再对比它们了😀,都挺好用的。
轮子推荐
好了,JSON才是主角,这里推荐几款c++中,JSON的第三方库不少,小到jsoncpp,大到boost,还有国产的rapidjson(腾讯)。而我要推荐的,是德国大牛nlohmann的JSON for Modern C++ ,github 地址:https://github.com/nlohmann/json.git。
推荐理由
很多时候,把变量写成json容易,可是把json变成变量就比较复杂。不过这对于nlohmann,一点都不复杂。
- 整个代码由一个头文件组成 json.hpp,没有子项目,没有依赖关系,没有复杂的构建系统,使用起来非常方便
- 语法直观,就像写普通的c++代码
- 不止用起来似c++习惯和风格,更是使用 C++ 11 标准编写
- 使用 json 像使用 STL 容器一样,STL 和 json 容器之间可以相互转换
- 严谨的测试:所有类都经过严格的单元测试,覆盖了 100% 的代码,包括所有特殊的行为。此外,还检查了 Valgrind 是否有内存泄漏。为了保持高质量,该项目遵循核心基础设施倡议(CII)的最佳实践
缺点(仁者见仁,智者见智)
- 可以确定的一个缺点,就是它只支持utf-8: 当使用与 UTF-8 不同编码的字符串在 JSON 中进行值存储时,由于仅支持 UTF-8,所以它们的序列化不能被库本身解析。为了强制实现这个库的限制并提高一致性,在序列化过程中,非 UTF-8 编码的字符串现在会产生一个 json::type_error 异常 (#838)。UTF-8 的有效性检验是通过 Björn Hoehrmann 的代码实现的。
- 二次封装在dll里面会报错,无法过编译。
- 不一定是缺点,那就是它对自定义类型的序列化是侵入式的。这个其实也不能说是缺点,下面顺带一下对侵入式和非侵入式的简要说明:
侵入式(引入或继承了别的包或框架)
从字面意思理解,就是你的代码里已经嵌入了别的代码,这些代码可能是你引入过的框架,也可能是你通过接口继承得来的(比如:java中的继承),这样你就可以拥有侵入代码的一些功能。所以我们就称这段代码是侵入式代码。非要说侵入式代码的优点:通过侵入代码与你的代码结合可以更好的利用侵入代码提供给的功能。缺点:框架外代码就不能使用了,不利于代码复用。依赖太多重构代码太痛苦了。
非侵入式
正好与侵入式相反,你的代码没有引入别的包或框架,完完全全是自主开发。比如golang中的结构体中的字段组合,这是非侵入式的,我完完全全可以其中某个字段的方法集合,或者我可以通过实现自己的方法集合从而达到剥离依赖关系的目的。优点:代码可复用,方便移植。非侵入式也体现了代码的设计原则:高内聚,低耦合。
我对前两点缺点的改良
第一点只支持utf-8,在windows平台可以使用如下方法:
MFC序列化中文的话,先定义一个字符转换方法`
std::wstring StoWs(const std::string& s)
{
int len;
int slength
= (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
以及
CString strName = (WCHAR*)(CA2W(j0Str.c_str(), CP_UTF8));
Qt中序列化中文更简单:
赋值给json:u8"中文";
读出来:QString qstr = QString::fromStdString(str);
第二点是…看项目源码吧,可以去找我的上传的资源,名为JsonSerialization。
https://download.csdn.net/download/weixin_37853132/12029689
Githubhttps://github.com/IInsect/JsonSerialization
就写到这里吧,没太大技术含量,也不想花太多精力。
使用说明可以参考下方
Qt简单例子
自定义类型
struct person
{
std::string name;
std::string address;
int age;
vector<int> vec;
};
void RegisterSerialization(json & j, const person & p) //注册
{
j = json{ {"name", p.name}, {"address", p.address}, {"age", p.age}, {"vec", p.vec} };
}
void RegisterDeserialization(const json & j, person & p)
{
p.name = j.at("name").get<std::string>();
p.address = j.at("address").get<std::string>();
p.age = j.at("age").get<int>();
p.vec = j.at("vec").get<vector<int>>();
}
/使用基本类型
json j0;
j0[u8"基本类型中文字符"] = u8"基本类型";
j0[u8"基本类型int"] = 9999;
j0[u8"基本类型string"] = "ABCDEFG123";
std::vector<int> c_vector{ 1, 2, 3, 4 };
j0[u8"基本类型vector"] = c_vector;
/使用自定义类型
person ppp;
ppp.address = "QtJson";
ppp.age = 99;
ppp.name = u8"佚名";
ppp.vec.push_back(1223);
ppp.vec.push_back(453);
ppp.vec.push_back(111);
ppp.vec.push_back(9999999);
json j1 = ppp;
DataSerialization *serialization = GetInstance(enumSerializationType::JsonSerialization);
serialization->Write("QtJson.json", j1);//将自定义类型的对象写到json文件
json j2;
serialization->Read("QtJson.json", j2);//从json文件读取赋值给自定义类型
person outPerson;
outPerson = j2;
std::string j0Str;
if (j0.find(u8"基本类型中文字符") != j0.end())
{
j0Str = j0[u8"基本类型中文字符"].get<std::string>();
}
/显示到界面
std::string str = j0Str + outPerson.address + outPerson.name;
QString qstr = QString::fromStdString(str);
ui.textEdit->setText(qstr);
MFC也一样的使用方法,只是涉及中文的时候,按我上面说的那种方式转换就好。
参考:
https://blog.csdn.net/fengxinlinux/article/details/71037244