Unreal Engine 5 C++中Protoc解析大于127的整数值时失败问题排查
解决UE5中Protobuf序列化二进制数据保存后解析失败的问题
你猜的完全正确!问题的核心就是把Protobuf的二进制序列化数据转成FString时的编码错误。下面我来拆解原因并给出完整的修复方案:
问题根源
Protobuf序列化出来的是纯二进制流,不是合法的UTF-8字符串:
- 当整型值≤127时,Varint编码只需要1字节,刚好是ASCII范围内的字符,转
FString时不会出问题; - 当值>127时(比如128),Varint会用多字节编码(128的编码是
0x80 0x01),这些字节不属于合法UTF-8字符; - 你用
FString(MyPlayerString.c_str())转换时,Unreal的FString会尝试把输入当作UTF-8解析,遇到无效字节会自动截断或替换,导致保存到文件的二进制数据已经损坏,protoc自然解析失败。
修复方案:用字节数组存储二进制数据
Unreal中处理二进制数据的标准方式是TArray<uint8>,它不会对内容做任何编码转换,能完整保留Protobuf的原始序列化结果。
修改后的序列化保存代码
com::game::Player MyPlayer; MyPlayer.set_username("test user name"); MyPlayer.set_experience(128); // 现在设为128也没问题了 // 序列化到std::string(注意:std::string在这里只是二进制容器,不是字符串) std::string MyPlayerBytes; if(!MyPlayer.SerializeToString(&MyPlayerBytes)) { UE_LOG(LogGameInstance, Error, TEXT("Can't serialize MyPlayer to bytes")); return; } // 转换为Unreal的字节数组,完整保留所有二进制数据 TArray<uint8> PlayerData; PlayerData.Append((const uint8*)MyPlayerBytes.data(), MyPlayerBytes.size()); // 保存到文件,直接用二进制模式保存字节数组 const FString File = *FPaths::Combine(FPaths::GameSourceDir(), FApp::GetProjectName(), TEXT("temp.dat")); if (!FFileHelper::SaveArrayToFile(PlayerData, *File)) { UE_LOG(LogGameInstance, Error, TEXT("Failed to save player data to file")); }
验证结果
运行修改后的代码后,执行命令:
protoc --decode_raw < temp.dat
会得到正确的输出:
1: "test user name" 2: 128
额外提示
如果之后需要从文件读取数据并解码,也要用FFileHelper::LoadFileToArray读取成TArray<uint8>,再转成std::string给Protobuf解码,避免同样的编码问题:
TArray<uint8> LoadedData; if (FFileHelper::LoadFileToArray(LoadedData, *File)) { std::string LoadedBytes((const char*)LoadedData.GetData(), LoadedData.Num()); com::game::Player LoadedPlayer; if (LoadedPlayer.ParseFromString(LoadedBytes)) { // 解码成功,处理数据 UE_LOG(LogGameInstance, Log, TEXT("Loaded player: %s, exp: %lld"), *FString(LoadedPlayer.username().c_str()), LoadedPlayer.experience()); } }
内容的提问来源于stack exchange,提问作者Vasyl Khvostyk




