读取 Json 数据,解析 Json 数组
版权声明:本文为CSDN博主「虎冯河」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
Json 格式示例:
{
"function": "Macro",
"params": {
"behaviors": [{
"behavior": {
"function": "1566",
"params": {
"duration": 6.37,
"filePath": "http://17/api/15"
}
},
"start_time": 0
},
{
"behavior": {
"function": "416546",
"params": {
"duration": 6.37,
"filePath": "http://175/915"
}
},
"start_time": 7.0
}
]
}
}
使用内置的 json 模块之前,在项目的 Build.cs 文件中,包含一下 Json 、JsonUtilities 模块。
解析 Json 的函数
void ParseJsonObject(const FString messageStr)
{
TSharedPtr<FJsonObject> jsonObject; // FJsonObject 类型
TSharedRef<TJsonReader<TCHAR>> jsonReader = TJsonReaderFactory<TCHAR>::Create(messageStr); // 类型转换
bool isSe = FJsonSerializer::Deserialize(jsonReader, jsonObject); // 序列化,返回 FJsonObject 类型数据
if (isSe) // 判断一下是否转换成功
{
FString func = jsonObject->GetStringField("function"); // function 字符串参数
FString content = jsonObject->GetStringField("content"); // content 字符串参数
TSharedPtr<FJsonObject> paramsObject = jsonObject->GetObjectField("params"); // params 参数 FJsonObject 类型
TArray<TSharedPtr<FJsonValue>> behaviorsArray = paramsObject->GetArrayField("behaviors"); // params下的 behaviors 数组参数
for (int i = 0; i < behaviorsArray.Num(); i++) // 遍历数组
{
FString timeStr = behaviorsArray[i]->AsObject()->GetStringField("start_time"); // behaviors 数组下的 behavior 的开始时间
float startTime = FCString::Atof(*timeStr); // 开始时间 float 类型
TSharedPtr<FJsonObject> behaviorObj = behaviorsArray[i]->AsObject()->GetObjectField("behavior"); // behaviors 数组下的 behavior 参数
FString beFuncStr = behaviorObj->GetStringField("function"); // behavior 下的 function 字符串参数
TSharedPtr<FJsonObject> beParam = behaviorObj->GetObjectField("params"); // behavior 下的 params 参数
FString filePathStr = beParam->GetStringField("filePath"); // params 参数下的 filePath 字符串参数
}
}
}
存储 Json 数据并输出字符串
作者:埃罗芒阿Sensal
一. 介绍
Json 是一种数据对象,数据由键值对组成.
- 简单的 Json 数据对象:
//{"键1":"值1","键2":"值2",....}
{"Name":"Tom","Age":"18","Sex":"man"}
- Json 对象作为键值对的值
// 班长信息:Json对象作为值
{"MonitorInfo":{"Name":"Tom","Age":"20","Sex":"man"}}
- Json 对象数组
[
// 第一个对象
{"Name":"Tom","Age":"18","Sex":"man"},
// 第二个对象
{"Name":"Jerry","Age":"17","Sex":"man"},
// 第三个对象
{"Name":"Lily","Age":"20","Sex":"woman"}
]
- Json 对象数组作为键值对的值
{
// 一班
"ClassNum":"1",
//老师叫张三
"TeacherName":"ZhangSan",
// 学生数组
"Students":
[
// 学生1
{"Name":"Tom","Age":"18","Sex":"man"},
// 学生2
{"Name":"Jerry","Age":"17","Sex":"man"},
// 学生3
{"Name":"Lily","Age":"20","Sex":"woman"}
]
}
二. UE4 Json 使用说明
使用 Json 模块需要在 Build.cs 中将 Json 模块导入
PublicDependencyModuleNames.AddRange(
new string[]
{
"Json"
}
);
1. FJsonObject 说明
FJsonObject 在 UE4 里表示一个 Json 对象,用于存储 Json 数据
(1) 初始化方式
/**
* 因为 FJsonObject 并非 UObjec t的派生类,无法自动进行垃圾回收,所以使用共享指针防止内存泄漏
* 下面定义一个空的 Json 对象
*/
TSharedPtr<FJsonObject> Object;
(2) FJsonObject 存储数据的几种形式
① 将常规类型作为值存储
// 1. 存储数据节点
// (1) SetStringField(FString key,FString value) 存储一个 FString 字段
Object->SetStringField(TEXT("Name"),TEXT("Tom"));
/**
* (2) SetNumberField(FString key,double value) 存储一个浮点型字段
*ps: 并没有 SetIntegerField , 存储整形也可以使用这个
*/
Object->SetNumberField(TEXT("Age"),18);
// (3) SetBoolField(FString key,bool value) 存储一个 bool 型字段
Object->SetBoolField(TEXT("IsMan"),true);
// 截止到次, Object 内的数据为 {"Name":"Tom", "Age":18, "IsMan":true}
- 实机测试代码如下
② 将 FJsonObject 作为值存储
//创建一个JsonObject
TSharedPtr<FJsonObject>Object= MakeShareable(new FJsonObject);
//填充字段信息
Object->SetStringField(TEXT("Name"), TEXT("Tom"));
Object->SetNumberField(TEXT("Age"), 18);
Object->SetBoolField(TEXT("IsMan"), true);
//创建另一个JsonObject作为上面的JsonObject中的一个字段的值
TSharedPtr<FJsonObject>obj = MakeShareable(new FJsonObject);
obj->SetNumberField(TEXT("weight"), 130);
obj->SetNumberField(TEXT("height"), 180);
obj->SetStringField(TEXT("Hobby"), TEXT("Game"));
//将obj作为Object中的Info字段的值
Object->SetObjectField(TEXT("Info"), obj);
- 实机测试代码
③.将 TArray<TSharedPtr<FJsonValue>> 作为值存储
结构大致如下
{
"field1":"xx",
"field2":"yy",
"fields":
[
// 切记! 数组中的元素必须要是字段都一致的 Json 对象,所有字段名都得是一样
{"Name":"tom","Age":18},
{"Name":"jerry","Age":17}
]
}
/**
*SetArrayField(FString key,TArray>value)
*存储一个数组作为某个字段的值
*/
// 1. 创建一个空的 FJsonValue 数组
TArray<TSharedPtr<FJsonValue>> JsonValueArray;
// 2. 创建两个 FJsonObject 作为数组元素
TSharedPtr<FJsonObject> vobj1 = MakeShareable(new FJsonObject);
vobj1->SetStringField(TEXT("familymember"), TEXT("Jerry"));
TSharedPtrv<FJsonObject> vobj2 = MakeShareable(new FJsonObject);
vobj2->SetStringField(TEXT("familymember"), TEXT("John"));
// 3. 将两个 FJsonObject 转化为 FJsonValue ,存储到数组中,到此数组填充完毕
JsonValueArray.Add(MakeShareable(new FJsonValueObject(vobj1)));
JsonValueArray.Add(MakeShareable(new FJsonValueObject(vobj2)));
Object->SetArrayField(TEXT("Famliy"), JsonValueArray);
/**
*截止到此 Object 内的信息
*{
* "Name":"Tom",
* "Age":18,
* "IsMan":true,
* "Family":
* [
* {"familymember":"Jerry"},
* {"familymember":"john"}
* ]
*}
*SetArrayField 要比其他的用法稍稍复杂一些,注意理解
*/
- 实机测试代码
(3)FJsonObject获取数据的方式
① 判断是否拥有某个字段
判断传入的字段是否存在, 在你想要查询某个字段的数据但是不确定 Json 中是否有这个字段时,可以先判断一下
进阶查询用法, 不光可以 判断字段是否存在 , 还能 判断字段的类型是否一致
② TryGetXXField
/**
* FieldName: 要查询的字段名
* OutValue: 该参数需要传入一个引用,用于接收查询到的结果
* 返回一个 bool 值,查询到数据返回 true ,查询不到返回 false
*/
TryeGetXXField(FString FieldName, XXType &OutValue);
// 假设一个简单的 json 对象(伪代码)
TSharedPtr<FJsonObject> obj = {"Name" : "Tom", "Age" : 18, "IsMan" : true};
FString OutString;
obj->TryGetStringField("Name", OutString); // OutString=Tom;
bool bIsMan = false;
obj->TryGetBoolField("IsMan", bIsMan); // bIsMan=true;
int32 age = 0;
// TryGetNumberField 可以支持获取 double int32 uint32 int64 类型的数值
obj->TryGetNumberField("Age", age); // age=18;
// obj 还能够获得 FJsonObject 和 TArray<FJsonValue> 数组
③ GetXXField
GetNumberField(获取浮点型数值) return double,GetBoolField(获取 bool 型数值) return bool ,GetArrayField(获取 FJsonValue 数组作为数值) return TArray<TSharedPtr>,GetObjectField(获取 FJsonObject 作为数值) return TSharedPtr.
说明:
使用 TryGet 和 Get 都可以用来获取数据,如果 Json 数据的字段是明确的,那么可以直接使用 Get 来获取. 如果不确定,可以使用 TryGet , 根据需求选择即可
(4) 逆序列化(Deserialize) FJsonObject
常用于将一个 FString 类型的 Json 数据存入到 FJsonObject 中
/**
*JsonStr 是 UE4 中的 Json 数据
*注意!!! 在 UE4 中需要使用\"(反斜杠+双引号,转义字符) 来替代"(双引号)
*看到 \" 直接在心里替换成 " 即可
*/
FString JsonStr = TEXT("{\"Name\":\"Tom\",\"Age\":\"18\",\"Sex\":\"man\"}");
// 使用工厂类,把 FString 格式的 Json 数据存到创建出来的 Json Reader 中
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonStr);
// 创建一个空的 JsonObject(Json 对象,因为其基类不是 UObject , 为了防止内存泄漏,使用共享指针)
TSharedPtr<FJsonObject> Object;
// FJsonSerializer 通过 Deserialize(逆序列化)拿 Reader 中存储的数据来填充空的 Json 对象
FJsonSerializer::Deserialize(Reader, Object);
//如果逆序列化成功, Json 对象 IsValid 将返回 true , 然后我们就可以通过他读取数据了
if (Object.IsValid())
{
// Json 对象通过 GetStringField,传入字段名(键),获得字符串类型的值
FString Name = Object->GetStringField(TEXT("Name"));
// Json 对象通过 GetIntegerField ,传入字段名(键),获得整形的值
int32 Age = Object->GetIntegerField(TEXT("Age"));
}
- 实机测试代码
(5) 序列化(Serialize) FJsonObject
常用于将 FJsonObject 中的数据写入到 FString 中
// 准备一个用于序列化的 FJsonObject
TSharedPtr<FJsonObject> Obj = MakeShareable(new FJsonObject);
Obj->SetStringField("Name", "Tom");
Obj->SetNumberField("Age", 18);
Obj->SetBoolField("IsMan", true);
// 创建一个空的 FString 用于接收序列化后的 json 数据
FString OutString;
TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&OutString);
// Serializer 将 Json 对象中的数据通过 Writer 写入到 outstring 中
bool bResult = FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
if (bResult)
{
UE_LOG(LogTemp, Warning, TEXT("serialize succeeded!! outstring:%s"), *OutString);
}
可以看到空的字符串被写入了数据
2. FJsonValue 说明
FJsonValue 在 UE4 中作为 Json 数据键值对中的值存在
(1) 初始化方式
FJsonValue 针对每一种 Json 值类型都进行了派生,引擎不提倡我们直接使用 FJsonValue 基类,而是提倡我们根据值类型来选择不同的派生类
派生类如下
1.FJsonValueString
// 初始化方式
TSharedPtr<FJsonValue> StrVal = MakeShareable(new FJsonValueString(""));
2.FJsonValueNumber
// 初始化方式
TSharedPtr<FJsonValue> numVal = MakeShareable(new FJsonValueNumber(""));
3.FJsonValueBoolean
// 初始化方式
TSharedPtr<FJsonValue> boolVal = MakeShareable(new FJsonValueBoolean(false));
4.FJsonValueObject
// 初始化方式
TSharedPtr<FJsonObject> Obj = MakeShareable(new FJsonObject);
TSharedPtr<FJsonValue> ObjVal = MakeShareable(new FJsonValueObject(Obj));
5. FJsonValueArray
// 初始化方式
TArray<TSharedPtr<FJsonValue>> InArray;
TSharedPtr<FJsonValue>ArrayVal = MakeShareable(new FJsonValueArray(InArray));
// 还有一些不太常用的派生类, 想了解更多可以去 Engine\Source\Runtime\Json\Public\Dom\JsonValue.h 中进行查看
(2) 常用节点
- ① AsXXX
根据选择的类型(FJsonValueXXX), 可以使用对应的 AsXXX 来获取数据内容
比如 FJsonValueString 可以使用 AsString 返回存储的字符串
- ② TryGetXXX
与 AsXXX 一样,根据类型来决定使用具体的 TryGetXXX 节点获取数据
3. 示例代码
// 创建主体 Json 对象
TSharedPtr<FJsonObject> TomObj = MakeShareable(new FJsonObject);
// 填充常规类型字段数据
TomObj->SetStringField("Name", "Tom");
TomObj->SetNumberField("Age", 18);
TomObj->SetBoolField("IsMan", true);
// 创建一个子 Json 对象作为值
TSharedPtr<FJsonObject> InfoObj = MakeShareable(new FJsonObject);
InfoObj->SetNumberField("Height", 180);
InfoObj->SetNumberField("Weight", 70);
TomObj->SetObjectField("Info", InfoObj);
// 创建两个子 Json 对象,数组的元素
TArray<TSharedPtr<FJsonValue>> ValueArray;
TSharedPtr<FJsonObject> FriendObj1 = MakeShareable(new FJsonObject);
TSharedPtr<FJsonObject> FriendObj2 = MakeShareable(new FJsonObject);
// 填充子对象数据
FriendObj1->SetStringField("Name", "jerry");
FriendObj1->SetNumberField("IsMan", true);
FriendObj2->SetStringField("Name", "lily");
FriendObj2->SetNumberField("IsMan", false);
ValueArray.Add(MakeShareable(new FJsonValueObject(FriendObj1)));
ValueArray.Add(MakeShareable(new FJsonValueObject(FriendObj2)));
TomObj->SetArrayField("Friends", ValueArray);
FString OutString;
TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&OutString);
bool bResult = FJsonSerializer::Serialize(TomObj.ToSharedRef(), Writer);
if (bResult)
{
UE_LOG(LogTemp, Warning, TEXT("serialize succeeded!! outstring:%s"), *OutString);
}