目标
尝试FArchive
的最基础功能。代码参考这里。
0. FArchive是什么?
源代码里FArchive
的注释如下:
Base class for archives that can be used for loading, saving, and garbage collecting in a byte order neutral way
- 它是 archive 的基类。(archive直译为“档案”,我理解是“存储数据的载体”)
- 在 读取、保存、垃圾回收的过程中发挥作用。
- 以字节顺序这样 neutral 的方式。(neutral直译为“中立的”,我理解是“通用的,并不特定针对于某一类型的”)
最常见的出现场合,应该是UObject序列化逻辑了。(“序列化”简单来说就是将自己的数据能保存下来,以便下次能读取回来)
1. 简单代码测试例:保存数据到文件
测试将一些数据写入文件:
- 首先,定义一些待存储的数据
- 然后,使用
CreateFileWriter
来创建一个用于保存数据的Archive - 最后,序列化数据。
//一些测试数据:
float TestF = 3.69;
FVector TestV = FVector(0.9, 0.5, 0.7);
FString TestS = "yak";
//创建用来保存数据的Archive
FArchive* TestArchive = IFileManager::Get().CreateFileWriter(TEXT("D:/Temp/TestArchive.dat"));
//序列化:
if (TestArchive)
{
*TestArchive << TestF;
*TestArchive << TestV;
*TestArchive << TestS;
TestArchive->Close();
}
运行后,可以看到文件被保存下来
2. 简单代码测试例:从文件读取数据
测试从刚才的文件中读取数据:
- 首先,由于数据是需要从文件读取出来的,而非定义的,所以开头只需要初始化即可。
- 然后,使用
CreateFileReader
来创建一个用于读取数据的Archive - 最后,反序列化数据,需要注意,这里和序列化时完全一样。
//初始化测试数据的值:
float TestF = 0;
FVector TestV = FVector(0, 0, 0);
FString TestS = "";
//创建用来保存数据的Archive
FArchive* TestArchive = IFileManager::Get().CreateFileReader(TEXT("D:/Temp/TestArchive.dat"));
//反序列化:
if (TestArchive)
{
*TestArchive << TestF;
*TestArchive << TestV;
*TestArchive << TestS;
TestArchive->Close();
}
//打印这些值看看:
UE_LOG(LogTemp, Warning, TEXT("TestF:%f TestV:%s TestS:%s"), TestF, *TestV.ToString(), *TestS);
运行后,可以看到能正确读取到之前的数据:
3. 为什么“反序列化”的代码和“序列化”的代码完全一样?
首先,从设计来说,读取必须一样。因为数据是按照顺序存入的,那么读取时也必须是一样的顺序。
如果尝试用不一样的顺序读取,则会有报错,且数据读取错误:
其次,从代码实现上讲,能做到完全一样是因为:不同的FArchive
子类可以对<<
操作有不同的逻辑。
比如,保存时,使用CreateFileWriter
创建出来的是FArchiveFileWriterGeneric
子类:
读取时,使用CreateFileReader
创建出来的是FArchiveFileReaderGeneric
:
这样,各种UObject序列化的代码只需要一个函数。这样不仅减少了代码维护,更重要的是能绝对保证反序列化时能与序列化有一致的顺序。