有没有办法标记每个 protobuf-net 记录的结尾
Posted
技术标签:
【中文标题】有没有办法标记每个 protobuf-net 记录的结尾【英文标题】:Is there a way to mark the end of each protobuf-net record 【发布时间】:2012-05-15 18:58:08 【问题描述】:我将一系列 protobuf-net 对象保存在数据库单元中作为长度前缀 protobuf-net 对象的 Byte[]:
//retrieve existing protobufs from database and convert to Byte[]
object q = sql_agent_cmd.ExecuteScalar();
older-pbfs = (Byte[])q;
// serialize the new pbf to add into MemoryStream m
//now write p and the new pbf-net Byte[] into a memory stream and retrieve the sum
var s = new System.IO.MemoryStream();
s.Write(older-pbfs, 0, older-pbfs.Length);
s.Write(m.GetBuffer(), 0, m.ToArray().Length); // append new bytes at the end of old
Byte[] sum-pbfs = s.ToArray();
//sum-pbfs = old pbfs + new pbf. Insert sum-pbfs into database
这很好用。我担心的是如果有轻微的数据库损坏会发生什么。将不再可能知道哪个字节是长度前缀,并且必须丢弃整个单元格内容。是否还建议使用某种类型的 pbf 对象结束指示符(有点像文本文件中使用的 \n 或 EOF 指示符)。这样,即使一条记录损坏,其他记录也可以恢复。
如果是这样,在每个 pbf 末尾添加记录结束指示符的推荐方法是什么。
在 Visual Studio 2010 上使用 protobuf-netv2 和 C#。
谢谢 马尼什
【问题讨论】:
【参考方案1】:如果您通过Serialize
/ Deserialize
使用普通消息,则不:这不是规范的一部分(因为格式被设计为可附加的)。
但是,如果您使用SerializeWithLengthPrefix
,它将在消息开头转储长度;然后它将提前知道需要多少数据。你用DeserializeWithLengthPrefix
反序列化,如果没有足够的数据它会大声抱怨。然而!如果您有 额外 数据,它不会抱怨,因为这个 too 被设计为可附加的。
就 Jon 的回复而言,*WithLengthPrefix
方法的默认用法就存储的数据而言与 Jon 建议的完全相同;它假装有一个包装对象并相应地表现。区别在于:
这里两个“可附加”的区别在于,第一个表示“合并为一个对象”,而第二个表示“我期望多个记录”。
不相关的建议:
s.Write(m.GetBuffer(), 0, m.ToArray().Length);
应该是:
s.Write(m.GetBuffer(), 0, (int)m.Length);
(无需创建额外的缓冲区)
【讨论】:
非常感谢。一个相关的问题。 Serializer 是否具有可用于通过网络发送 Byte[] sum-pbfs 的方法。标准机制似乎是循环遍历 Byte[] 直到你到达终点。但是像 Serializer.send(clientStream, sum-pbfs) 这样的东西会很棒。 @Manish 我不明白这个问题;什么是“sum-pbfs”?如果使用 WithLengthPrefix 方法,它不会读取一条消息。您还可以创建一个固定长度的 ProtoReader IIRC,并使用它 - 或者可能有一个接受固定长度的反序列化重载(不记得,但在公共 API 上绝对很容易完成) 我很抱歉不够清晰。 sum-pbfs 在上面的代码 sn-p 中,它本质上是一个序列化 pbfs 的 Byte[]。通过套接字发送 byte[] 的所有示例都表明我们一次循环通过它 2kb。我希望可能有一种更简单的方式来传输字节 []。但是在你的cmetshere之后,我想我还是会一次发送一个pbf。谢谢。【参考方案2】:(注意:我对protobuf-net本身了解不多,但这一般适用于Protocol Buffer消息。)
通常,如果您想记录多条消息,只需放置一个“包装器”消息 - 使“真实”消息成为其中的重复字段。然后,每个“真实”消息的长度都会以 Protocol Buffers 的自然线格式为前缀。
这当然不会检测到损坏 - 但老实说,如果数据库最终损坏,您就会遇到更大的问题。您可能检测损坏,例如通过将散列与每条记录一起保存......但您需要考虑在长度前缀内或散列本身内发生损坏的可能性。想一想您在此处真正想要达到的目标 - 您想要防范的场景以及您需要的恢复水平。
【讨论】:
非常感谢您的反馈。我终于找到了一种方法来查看 protobuf-net 是否允许重复字段。事实并非如此。我可以看到一个字段的 IsRepeated = True 选项,但不是 IsRepeated = True。 @Manish:它肯定会处理重复的字段。我希望它们被建模为集合。以上是关于有没有办法标记每个 protobuf-net 记录的结尾的主要内容,如果未能解决你的问题,请参考以下文章
在 protobuf-net 中,有没有办法指定在序列化/反序列化给定类型时要使用的自定义方法?
有没有办法将 IReadOnlyCollection<T>/IReadOnlyList<T> 与 protobuf-net 一起使用
Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录