你的浏览器不支持canvas

让我们携手共创奇迹!

Json读写

Date: Author: LBD

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。转载请注明来自WindCrazy

一些关于Json文件的读写知识

参考:【UE4】文件系统

一、准备

UE中想进行基础的读写Json文件需要引入模块:在.Build.cs文件中添加一行,"Json"

using UnrealBuildTool;
public class PakTest : ModuleRules
{
	public PakTest(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
		PublicDependencyModuleNames.AddRange(new string[]
		{
			"Core",
			"CoreUObject", 
			"Engine", 
			"InputCore", 
			"PakFile",
			"Json"//,
			//"JsonUtilities"//后面会说,基础的读写用不到
		});
	}
}

二、FJsonObject, FString, 文件

void ALoadPakActor::JsonSerializeTest(const FString& FilePath)
{
	TSharedPtr<FJsonObject> rootObj = MakeShareable(new FJsonObject());//首先创建一个FJsonObject对象
	rootObj->SetStringField("root", "1");
	rootObj->SetBoolField("bIsTest",false);
	
	//rootObj->SetObjectField("secondRoot",rootObj);//Error
	TSharedPtr<FJsonObject> SecondRoot = MakeShareable(new FJsonObject());
	TSharedPtr<FJsonValue> testValue = MakeShareable(new FJsonValueNumber(8.4));
	SecondRoot->SetField("valueKey",testValue);
	rootObj->SetObjectField("secondRoot", SecondRoot);

	TSharedPtr<FJsonObject> ThirdRoot = MakeShareable(new FJsonObject());
	ThirdRoot->SetObjectField("SecondRoot",SecondRoot);//可以重复使用,上面那个不行猜测是循环嵌套
	rootObj->SetObjectField("ThirdRoot", ThirdRoot);
	
	TArray<TSharedPtr<FJsonValue>> arrValue;
	TSharedPtr<FJsonValueString> tmp = MakeShareable(new FJsonValueString("array"));
	arrValue.Add(tmp);
	tmp = MakeShareable(new FJsonValueString("9.2"));
	arrValue.Add(tmp);
	tmp = MakeShareable(new FJsonValueString("9.2adg"));
	arrValue.Add(tmp);
	arrValue.Add(testValue);//可以重复使用
	rootObj->SetArrayField("array", arrValue);
	
	FString jsonStr;
	TSharedRef<TJsonWriter<TCHAR>> jsonWriter = TJsonWriterFactory<TCHAR>::Create(&jsonStr);//写入一样需要绑定一个FString作为输入流载体
	FJsonSerializer::Serialize(rootObj.ToSharedRef(), jsonWriter);//序列化写好的FJsonObject对象需要转化为FString字符串才能向文本中写入数据
	FFileHelper::SaveStringToFile(jsonStr, *FilePath);
	UE_LOG(LogTemp, Warning, TEXT("JsonData%s"),*jsonStr);
}

写入之后长这样

{
	"root": "1",
	"bIsTest": false,
	"secondRoot":
	{
		"valueKey": 8.4000000000000004
	},
	"ThirdRoot":
	{
		"SecondRoot":
		{
			"valueKey": 8.4000000000000004
		}
	},
	"array": [
		"array",
		"9.2",
		"9.2adg",
		8.4000000000000004 ]
}
void ALoadPakActor::JsonDeserializeTest(const FString& FilePath)
{
	if (FPaths::FileExists(FilePath))
	{
		FString fileStr;
		FFileHelper::LoadFileToString(fileStr, *FilePath);//首先Json文本的读取需要将Json文本以字符串的形式读入到一个FString的输入流载体中
		TSharedRef<TJsonReader<>> jsonReader = TJsonReaderFactory<>::Create(fileStr);//然后我们需要将这个输入流载体绑定到TJsonReader<>读出工具上
		TSharedPtr<FJsonObject> rootObject = MakeShareable(new FJsonObject());
		if (FJsonSerializer::Deserialize(jsonReader, rootObject))//然后将输入流载体的Json数据反序列化到FJsonObject对象中
		{
			UE_LOG(LogTemp, Warning, TEXT("root:%s"),*rootObject->GetStringField("root"));
			UE_LOG(LogTemp, Warning, TEXT("bIsTest:%d"),rootObject->GetBoolField("bIsTest"));
			UE_LOG(LogTemp, Warning, TEXT("secondRoot-valueKey:%f"),rootObject->GetObjectField("secondRoot")->GetNumberField("valueKey"));
			UE_LOG(LogTemp, Warning, TEXT("ThirdRoot-SecondRoot-valueKey:%f"),rootObject->GetObjectField("ThirdRoot")->GetObjectField("SecondRoot")->GetNumberField("valueKey"));

			TArray<TSharedPtr<FJsonValue>> Array;
			Array = rootObject->GetArrayField("array");
			for (auto JsonValue : Array)
			{
				//UE_LOG(LogTemp, Warning, TEXT("array:%s"),*JsonValue.Get()->AsString());
				UE_LOG(LogTemp, Warning, TEXT("array:%f"),JsonValue.Get()->AsNumber());
			}
		}
	}
}

三、JsonUtilities

这个其实挺常用的,可能常用的有FJsonDomBuilder, FJsonObjectConverter

FJsonDomBuilder让上面构造FJsonObject更方便

/**
 * Helpers for creating TSharedPtr<FJsonValue> JSON trees
 *
 * Simple example:
 *
 *	FJsonDomBuilder::FArray InnerArray;
 *	InnerArray.Add(7.f, TEXT("Hello"), true);
 *
 *	FJsonDomBuilder::FObject Object;
 *	Object.Set(TEXT("Array"), InnerArray);
 *	Object.Set(TEXT("Number"), 13.f);
 *
 *	Object.AsJsonValue();
 *
 * produces {"Array": [7., "Hello", true], "Number": 13.}
 */
class FJsonDomBuilder

FJsonObjectConverterFJsonObject和你的结构体转换更方便,简单使用可以下面视频和代码

LoadPakActor.h

USTRUCT(BlueprintType)
struct FMyJsonStruct
{
	GENERATED_BODY()
public:
	UPROPERTY(BlueprintReadWrite)
	FString Name;
	UPROPERTY(BlueprintReadWrite)
	int Age;
};
UCLASS()
class PAKTEST_API ALoadPakActor : public AActor
{
	GENERATED_BODY()
public:	
	UFUNCTION(BlueprintCallable)
	FMyJsonStruct ConvertStringToJsonStruct(const FString& JsonContent);

	UFUNCTION(BlueprintCallable)
	FString ConvertJsonStructToString(const FMyJsonStruct& JsonStruct);
};

LoadPakActor.cpp

FMyJsonStruct ALoadPakActor::ConvertStringToJsonStruct(const FString& JsonContent)
{
	FMyJsonStruct MyJsonStruct;
	if (!FJsonObjectConverter::JsonObjectStringToUStruct(JsonContent, &MyJsonStruct))
	{
		UE_LOG(LogTemp, Warning, TEXT("JsonObjectStringToUStruct - Unable to parse json=[%s]"), *JsonContent);
	}
	return MyJsonStruct;
}

FString ALoadPakActor::ConvertJsonStructToString(const FMyJsonStruct& JsonStruct)
{
	FString JsonContent;
	if (!FJsonObjectConverter::UStructToJsonObjectString(JsonStruct, JsonContent))
	{
		UE_LOG(LogTemp, Warning, TEXT("UStructToJsonObjectString - Unable to write out JSON: %s"), *JsonStruct.StaticStruct()->GetName());
		JsonContent = "Error";
	}
	return JsonContent;
}

对应Json文件格式为,并且从蓝图运行情况来看不区分大小写因为UPROPERTY宏做了处理(必须加这个宏,不加无法Convert),但是最好还是养好习惯

{
    "name": "李明",
    "age": 18
}

对于本文内容有问题或建议的小伙伴,欢迎提出问题