有没有办法标记每个protobuf-net记录的结尾

时间:2012-05-15 18:58:08

标签: c# protobuf-net

我将数据库单元格中的一系列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-object结尾指示符(类似于文本文件中使用的\ n或EOF指示符)。这样即使记录被破坏,其他记录也是可以恢复的。

如果是这样,在每个pbf结束时添加记录结束指标的建议方法是什么。

在Visual Studio 2010上使用protobuf-netv2和C#。

由于 和Manish

2 个答案:

答案 0 :(得分:3)

如果您通过Serialize / Deserialize使用vanilla消息,则no:这不是规范的一部分(因为格式设计为可附加的)。

但是,如果使用SerializeWithLengthPrefix,它将在消息开头转储长度;然后它会事先知道预期有多少数据。您使用DeserializeWithLengthPrefix反序列化,如果没有足够的数据,它会大声抱怨。然而!如果你有额外的数据,它不会抱怨,因为设计为可附加的。

就Jon的回复而言,*WithLengthPrefix方法的默认用法是,根据存储的数据与Jon建议完全相同;它假装有一个包装器对象并且相应地表现。不同之处是:

  • 实际上没有包装对象
  • “withlengthprefix”方法在一次出现后显式停止,而不是将任何后续数据合并到同一对象中(例如,将多个谨慎对象发送到单个文件或单个套接字时很有用)

这两个“可附加”的区别在于第一个意味着“合并为单个对象”,其中第二个意思是“我期望多个记录”。

无关的建议:

s.Write(m.GetBuffer(), 0, m.ToArray().Length);

应该是:

s.Write(m.GetBuffer(), 0, (int)m.Length);

(无需创建额外的缓冲区)

答案 1 :(得分:2)

(注意:我对protobuf-net本身了解不多,但这通常适用于Protocol Buffer消息。)

通常,如果你想记录多条消息,那么只需要输入一个“包装”消息 - 将“真实”消息作为重复字段。然后,每个“真实”消息的长度前缀为协议缓冲区的自然线格式。

这当然不会检测到腐败 - 但说实话,如果数据库最终被破坏,你就会遇到更大的问题。您可能会检测损坏,例如通过保持散列以及每条记录......但是您需要考虑在长度前缀内或散列本身内发生损坏的可能性。想想你想要在这里实现的目标 - 你想要防范的场景,以及你需要什么级别的恢复。