gpt4 book ai didi

python - 反序列化带有 header 和重复字段的流 Protocol Buffer 消息

转载 作者:行者123 更新时间:2023-12-04 10:42:51 26 4
gpt4 key购买 nike

我正在使用 Protocol Buffer (和 NanoPB)反序列化已在 C 中序列化的日志文件。

日志文件有一个简短的标题,包括:实体、版本和标识符。在 header 之后,数据流应该是连续的,它应该记录来自传感器的字段而不是 header 值(这应该只在开始时出现一次)。相同的 .proto 文件用于序列化文件。我没有单独的 .proto 文件用于 header 和流数据。

在我实现之后,我认为它应该是这样的:

firmware "1.0.0"
GUID "1231214211321" (example)
Timestamp 123123
Sens1 2343
Sens2 13123
Sens3 13443
Sens4 1231
Sens5 190
Timestamp 123124
Sens1 2345
Sens2 2312
...

我发了 this question弄清楚最初如何构建 .proto 文件,当我在 C 中实现序列化时。最后我使用了类似的方法,但没有包括:[(nanopb).max_count = 1];

最后,我在 Python 中选择了以下 .proto(传感器可以多于 5 个):
syntax = "proto3";

import "timestamp.proto";

message SessionLogs {
int32 Entity = 1;
string Version = 2;
string GUID = 3;
repeated SessionLogsDetail LogDetail = 4;
}
message SessionLogsDetail
{
int32 DataTimestamp = 1; // internal counter to identify the order of session logs
// Sensor data, there can be X amount of sensors.
int32 sens1 = 2;
int32 sens2= 3;
int32 sens3= 4;
int32 sens4= 5;
}

在这一点上,我可以在使用设备登录时序列化一条消息,并且根据文件大小,日志似乎可以工作,但我无法在 Python 离线上反序列化它以检查我的实现是否正确。我不能用 C 来做,因为它是一个嵌入式应用程序,我想用 Python 进行离线后处理。

另外,我查了 this online protobuf deserializer我可以传递序列化文件并在不需要 .proto 文件的情况下将其反序列化。在其中我可以看到标题值(字段 3 为空,因此看不到)和记录的信息。所以这让我认为序列化是正确的,但我在 Python 上错误地反序列化了它。

Output of the deserializer

这是我当前用于在 Python 中反序列化消息的代码:
import PSessionLogs_pb2

with open('$PROTOBUF_LOG_FILENAME$', 'rb') as f:
read_metric = PSessionLogs_pb2.PSessionLogs()
read_metric.ParseFromString(f.read())

除此之外,我还使用 protoc 生成 .py 等效的 .proto 文件以离线反序列化。

最佳答案

看起来您已经序列化了一个 header ,然后立即序列化了一些其他数据,这意味着:不是序列化具有一些 SessionLogsDetail 记录的 SessionLogs,而是序列化了一个 SessionLogs,然后您(单独)序列化了一个 SessionLogsDetail -那个听起来是对的吗?如果是这样:是的,这将无法正常工作;有很多方法可以做你想做的事,但它并不像一个接一个地序列化那么简单,因为根 protobuf 对象 永不终止 ;所以实际发生的是它用数字覆盖了后面的字段的根对象。

有两种方法可以解决这个问题,具体取决于数据量。如果大小(包括所有细节行)很小,您只需更改代码,使其成为真正的父/子关系,即行都在父级内。写入数据时,这并不意味着您需要在开始写入之前拥有所有行 - 有多种方法可以附加子行,以便您在数据可用时发送;但是,在反序列化时,它会想要一次性加载所有内容,因此这种方法仅在您对此感到满意时才有用,即您没有淫秽的开放式行数。

如果您有大量行,则基本上需要添加自己的框架。这通常是通过在每个有效负载之间添加长度前缀来完成的,这样您基本上可以一次读取一条消息。一些库为此包含辅助方法;例如,在 java API 中,这是 parseDelimitedFromwriteDelimitedTo .但是,我的理解是 python API 目前不支持这个实用程序,所以你需要自己做框架 :(

总而言之,您目前拥有:

{header - SessionLogs}
{row 0 - SessionLogsDetail}
{row 1 - SessionLogsDetail}

选项 1 是:
{header - SessionLogs
{row 0 - SessionLogsDetail}
{row 1 - SessionLogsDetail}
}

选项 2 是:
{length prefix of header}
{header - SessionLogs}
{length prefix of row0}
{row 0 - SessionLogsDetail}
{length prefix of row1}
{row 1 - SessionLogsDetail}

(其中长度前缀很简单,比如原始 varint,或者只是一个 4 字节整数,符合某种约定的字节序)

关于python - 反序列化带有 header 和重复字段的流 Protocol Buffer 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59847542/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com