Published on

Json文件读写

本文主要介绍UE4下的JSON文件的读写

文件读写

首先我们需要扩展普通的文件读写方法

bool UTestLib::V_LoadStringFromFile(const FString& FileName, const FString& RelativePath, FString& result)
{
	if (!FileName.IsEmpty())
	{
		FString file=FPaths::ProjectContentDir()+RelativePath+FileName;
		return  FFileHelper::LoadFileToString(result,*file);				
		
	}
	return false;
}
bool UTestLib::V_SaveStringToFile(const FString& FileName, const FString& RelativePath, const FString& string)
{

	if (!FileName.IsEmpty())
	{
		FString file = FPaths::ProjectContentDir() + RelativePath + FileName;
		return  FFileHelper::SaveStringToFile(string,*file);

	}
	return false;
}

此方法是以工程目录下的Content路径为基础的,如果需要指定其他路径就需要替换 FPaths::ProjectContentDir()方法或者干脆直接把整个路径给公开

JSON文件读写

先来一个示例JSON文件

{
    "school": "Super",
	"name":
	[
		"Tom",
		"Jien",
		"Harry"
	],
	"Tom":
	{
		"sex":"boy",
		"score":
		{
			"Math":99,
			"English":80
		}
	},
	"Jien":
	{
		"sex":"boy",
		"score":
		{
			"Math":88,
			"English":95
		}
	}
}

解释几个关键参数

  • TJsonReader
`TSharedPtr<FJsonObject>` JSONContentObject;
TSharedRef<`TJsonReader<TCHAR>`> Reader = `TJsonReaderFactory<TCHAR>`::Create(JSONInput);

用来反序列化的一个类,把文件中的字符串先存放到TJsonReader的智能指针里;同样的还有写入操作和序列化操作,对应的类就是TJsonWriter

  • FJsonObject
FJsonSerializer::Deserialize(Reader, JSONContentObject)

通过FJsonSerializerTJsonReader 反序列化到FJsonObject中,然后就可以通过方法来解读

StringValue=JSONContentObject->GetStringField(key);

当然,有个前提是这个key对应的一个值,如示例中的"school": "Super

  • FJsonValue

因为JSON文件是可以使用数组和嵌套的,对于数组,就必须用到FJsonValue

/*
"name":
	[
		"Tom",
		"Jien",
		"Harry"
	],
*/

TArray<`TSharedPtr<FJsonValue>`> JsonParedValue;
`TSharedPtr<FJsonObject>` JsonObj;
if (FJsonSerializer::Deserialize(JsonReader, JsonObj))
{
	JsonParedValue = JsonObj->GetArrayField(key);
}

因为name对应的是一个数组,所以得到的FJsonValue就是这个数组的成员

然后通过下面方法得到所有成员

for (auto i: JsonParedValue)
{
    value.Add(i->AsString());
}

完整的解析一个键值对,值是数组的方法如下

bool UTestLib::V_LoadValueArrayFromJsonKey(const FString& JsonString, const FString& key, `TArray<FString>`& value)
{
	TArray<`TSharedPtr<FJsonValue>`> JsonParedValue;
	`TSharedPtr<FJsonObject>` JsonObj;
	TSharedRef<`TJsonReader<TCHAR>`> JsonReader = `TJsonReaderFactory<TCHAR>`::Create(JsonString);
	if (FJsonSerializer::Deserialize(JsonReader, JsonObj))
	{
		JsonParedValue = JsonObj->GetArrayField(key);
		
		for (auto i: JsonParedValue)
		{
			value.Add(i->AsString());
		}
		return true;
	}
	return false;
}

简单的键值对的方法如下

bool UTestLib::V_LoadValueFromJsonKey(const FString& JsonString, const FString& key, FString& value)
{
	TArray<`TSharedPtr<FJsonValue>`> JsonParedValue;
	`TSharedPtr<FJsonObject>` JsonObj;
	TSharedRef<`TJsonReader<TCHAR>`> JsonReader=`TJsonReaderFactory<TCHAR>`::Create(JsonString);
	if (FJsonSerializer::Deserialize(JsonReader, JsonObj))
	{
		value=JsonObj->GetStringField(key);
		return true;
	}
	return false;
}

写入会麻烦一点,首先需要些一个函数来把FJsonObject转换为FString

bool UTestLib::GetStringFromJsonObj(const `TSharedPtr<FJsonObject>`& InJsonObj, FString& OutStr)
{
	if (InJsonObj.IsValid() && InJsonObj->Values.Num() > 0)
	{
		TSharedRef<`TJsonWriter<TCHAR>`> t_writer = TJsonWriterFactory<>::Create(&OutStr);
		FJsonSerializer::Serialize(InJsonObj.ToSharedRef(), t_writer);
		return true;
	}
	return false;
}

然后我们直接写一个改写固定键值对的函数

bool UTestLib::V_SaveJsonData(const FString& FileName, const FString& RelativePath, const FString& key, const FString& value)
{
	FString JsonString;
	FString result;
	if (V_LoadStringFromFile(FileName, RelativePath, JsonString))
	{
		TArray<`TSharedPtr<FJsonValue>`> JsonParedValue;
		`TSharedPtr<FJsonObject>` JsonObj;
		TSharedRef<`TJsonReader<TCHAR>`> JsonReader = 	`TJsonReaderFactory<TCHAR>`::Create(JsonString);
		if (FJsonSerializer::Deserialize(JsonReader, JsonObj))
		{
			JsonObj->SetStringField(key,value);
		if (GetStringFromJsonObj(JsonObj, result))
            {
                return V_SaveStringToFile(FileName, RelativePath, result);
            }		
		}
	}
	return false;

}

最后得到结果


\
    {
	"school": "hello",
	"name": [
		"Tom",
		"Jien",
		"Harry"
	],
	"Tom":..........
}