最近需要用C++实现JSON的序列化与反序列化,在网上苦苦找寻,一开始相中了Jsoncpp,下载下来苦苦编译啊,设置是真心头疼,对于我这个小白来说是真麻烦呀。各种大神的各种经验完全不管用,最后碰巧看到了这个德国大神的巨作。就是我送给你们的玩具啦~~
首先引用两个中文 博客,因为我英文较差,看中文还比较轻松一些。所以从一开始接触这个库就是靠的这两个大神指引道路的。
废话不多说了,那两个博客写的比较详细了,但是我感觉我还是的把我经常用到的功能列出来,也可以补充一下前辈没有说明的东西。
一、国际惯例,使用背景
在自己的项目中添加头文件
#include "json.hpp"
using namespace std;
using json = nlohmann::json;
完美~
using json = nlohmann::json
使用C++风格的重命名
二、从文件中读取多个json对象
从文件中读取多个JSON对象并把每个对象中的每个key读出来
json j;
ifstream ifile("logService.json");
if (ifile.fail()) {
cout << "..." << endl;
return 0;
}
string str;
while (!ifile.eof())
{
std::getline(ifile, str);
j = json::parse(str);
cout << setw(4) << j << endl;
cout << "++++++++++++++++++++++++++++++++";
for (json::iterator i = j.begin(); i != j.end(); ++i)
{
cout << "key:"<<i.key()<< endl;
}
}
JSON.hpp中支持了STL的语法,可以用迭代器。
Json文件中不可以有换行符\n
更新一波吧,下面是json to class 的反序列化测试代码,序列化函数为 json.dump(),json库内的操作就不重复了。
#include "nlohmann/json.hpp"
using json = nlohmann::json;
enum class Type
{
kType1 = 0,
kType2 = 1,
kType3 = 2,
kType4 = 3,
kType5 = 4
};
NLOHMANN_JSON_SERIALIZE_ENUM(Type, {
{Type::kType1, nullptr},
{Type::kType2, "stopped"},
{Type::kType3, "running"},
{Type::kType4, "completed"},
{Type::kType5, "completed"},
});
class TestType
{
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestType, test1, test2, test3, test4);
int test1, test2, test3;
Type test4;
};
class TestType2
{
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestType2, test21, test22, test23);
int test21, test22;
TestType test23;
};
class TestType3 :public TestType
{
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestType3, test1, test2, test3, test4, test31, test32);
int test31, test32;
};
class TestType4 :public TestType
{
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(TestType4, test1, test2, test3, test4, test41, test42, test43);
int test41, test42;
TestType test43;
};
int main()
{
json j = Type::kType2;
assert(j == "stopped");
//// json string to enum
json j3 = "running";
assert(j3.get<Type>() == Type::kType3);
//// undefined json value to enum (where the first map entry above is the default)
json jPi = 3.14;
assert(jPi.get<Type>() == Type::kType1);
json j2 = "{\"test1\":1,\"test2\":2,\"test3\":3,\"test4\":\"stopped\"}"_json;
TestType test(j2);
assert(test.test1 == 1);
assert(test.test2 == 2);
assert(test.test3 == 3);
assert(test.test4 == Type::kType2);
json j4 = "{\"test21\":21,\"test22\":22,\"test23\":{\"test1\":1,\"test2\":2,\"test3\":3,\"test4\":\"stopped\"}}"_json;
TestType2 test2(j4);
assert(test2.test21 == 21);
assert(test2.test22 == 22);
assert(test2.test23.test1 == 1);
assert(test2.test23.test4 == Type::kType2);
json j5 = "{\"test1\":1,\"test2\":2,\"test3\":3,\"test4\":\"stopped\",\"test31\":31,\"test32\":32}"_json;
TestType3 test3(j5);
assert(test3.test1 == 1);
assert(test3.test2 == 2);
assert(test3.test3 == 3);
assert(test3.test4== Type::kType2);
assert(test3.test31 == 31);
assert(test3.test32 == 32);
json j6 = "{\"test1\":1,\"test2\":2,\"test3\":3,\"test4\":\"stopped\",\"test41\":31,\"test42\":32,\"test43\":{\"test1\":1,\"test2\":2,\"test3\":3,\"test4\":\"stopped\"}}"_json;
TestType4 test4(j6);
assert(test4.test1 == 1);
assert(test4.test2 == 2);
assert(test4.test3 == 3);
assert(test4.test4 == Type::kType2);
assert(test4.test41 == 31);
assert(test4.test42 == 32);
assert(test4.test43.test1 == 1);
assert(test4.test43.test4 == Type::kType2);
return 0;
}
再额外写一点自己的代码吧~~
下面代码主要目的是为了让逻辑代码与Josn库解耦,就是万一想换Json库时只想改一个文件,这样的化其他取值的文件不能直接使用该Json 库,实际开发中也确实遇到了这样的情况,想换jsoncpp那个库,就改了一下里面的代码就可以啦~~
class config
{
using json = nlohmann::json;
protected:
config() = default;
virtual ~config() = 0;
bool LoadFromFile(std::string file_name);
template <typename T>
T GetValue(const std::string& key)
{
return json_data_.value(key, T{});
}
template <typename T>
void GetValue(const std::string& key, T& value)
{
value = json_data_.value(key, value);
return;
}
private:
std::string file_name_;
json json_data_;
};
struct SiXXXXXXConf
{
NLOHMANN_DEFINE_TYPE_INTRUSIVE(SiXXXXXXConf, ip_, port_, stxxxxxxxxer_
, tuxxxxxxxxr_, xxxxxxxxxxxame_, xxxxxxxxxxxxntial_);
SiXXXXXXConf()
: ip_{ }, port_{ 0 }
, stxxxxxxxxer_{}
, tuxxxxxxxxr_{}, xxxxxxxxxxxame_{}, xxxxxxxxxxxxntial_{} {}
std::string ip_;
utint32 port_;
std::string stxxxxxxxxer_;
std::string tuxxxxxxxxr_;
std::string xxxxxxxxxxxame_;
std::string xxxxxxxxxxxxntial_;
};
class Webxxxxxxxig : public config
{
using WConfig = std::variant<utint32, std::string, Rect, SiXXXXXXConf, ControllerConf, std::vector<std::string>, CodecConf>;
public:
Webxxxxxxxig();
Webxxxxxxxig(const std::string& config_file_name);
Webxxxxxxxig(const Webxxxxxxxig& config);
~Webxxxxxxxig();
bool LoadConfig()
{
ASSERT_EQUEL_RETURN(config_file_name_, "", false);
ASSERT_NOTEQUEL_RETURN(LoadFromFile(config_file_name_), true, false);
conxxxxxxxxtainer_["locaxxxxme_"] = GetValue<std::string>("locaxxxxme_");
conxxxxxxxxtainer_["remoxxxxames_"] = GetValue<std::vector<std::string>>("remoxxxxames_");
conxxxxxxxxtainer_["scrxxxxxxxze_"] = GetValue<Rect>("screen-size_");
conxxxxxxxxtainer_["signaxxxxxxxnfig__"] = GetValue<SiXXXXXXConf>("signaxxxxxxxnfig__");
conxxxxxxxxtainer_["controlxxxxxonfig_"] = GetValue<ControllerConf>("controlxxxxxonfig_");
}
bool LoadConfig(const std::string& config_file_name);
template<typename T>
T Get(const std::string key) const
{
T ret{};
auto it = conxxxxxxxxtainer_.find(key);
if (it != conxxxxxxxxtainer_.end()) ret = std::get<T>(it->second);
return ret;
}
template<typename T>
void Get(const std::string key, T& out_data) const
{
auto it = conxxxxxxxxtainer_.find(key);
if (it != conxxxxxxxxtainer_.end()) out_data = std::get<T>(it->second);
}
private:
std::string config_file_name_;
std::map<std::string, WConfig> conxxxxxxxxtainer_;
};
缺少了部分无关紧要的代码,小伙伴自己脑补吧~~值得注意的是 Variant 这个是C++17标准库中的联合变量,自己调整编译器的C++支持标准吧,vs2019是c++14起。
上面的WebrtcConfig 那个类主要目的就是把所有的配置从json 中读出来,然后放到容器中,为了让容器可以存储不同类型的变量,我使用了标准库中联合变量,取出的后就不再访问json 库了,取配置是直接访问容器,当然还没有写Json 文件的操作,后面加上再补吧,现在没有这个需要求。
本文详细介绍如何使用nlohmann JSON库进行C++中的JSON序列化与反序列化,包括基本使用、从文件读取JSON、类型转换及复杂数据结构处理,通过实例演示如何将JSON字符串转换为C++类。
1262

被折叠的 条评论
为什么被折叠?



