如何使用 protobuf-net 读回附加的对象?
Posted
技术标签:
【中文标题】如何使用 protobuf-net 读回附加的对象?【英文标题】:How to read back appended objects using protobuf-net? 【发布时间】:2013-08-24 18:28:38 【问题描述】:我正在使用 protobuf-net 序列化将实时事件附加到文件流中。如何将所有保存的对象流回以供分析?我不想使用内存中的集合(因为它会很大)。
private IEnumerable<Activity> Read()
using (var iso = new IsolatedStorageFileStream(storageFilename, FileMode.OpenOrCreate, FileAccess.Read, this.storage))
using (var sr = new StreamReader(iso))
while (!sr.EndOfStream)
yield return Serializer.Deserialize<Activity>(iso); // doesn't work
public void Append(Activity activity)
using (var iso = new IsolatedStorageFileStream(storageFilename, FileMode.Append, FileAccess.Write, this.storage))
Serializer.Serialize(iso, activity);
【问题讨论】:
【参考方案1】:首先,我需要讨论 protobuf 格式(通过 Google,不特定于 protobuf-net)。按照设计,它是可附加的,但带有 append===merge。对于列表,这意味着“作为新项目附加”,但对于单个对象,这意味着“组合成员”。其次,由于上述原因,protobuf 中的根对象永远不会终止 - “结束”很简单:当你用完传入的数据时。第三,同样作为直接结果 - 字段不需要按任何特定顺序排列,并且通常会覆盖。所以:如果您只是多次使用 Serialize,然后读回数据:您将只有一个对象,它基本上将具有流中最后一个对象的值。
不过,您想要做的是一个非常常见的场景。所以 protobuf-net 通过包含 SerializeWithLengthPrefix 和 DeserializeWithLengthPrefix 方法来帮助你。如果您使用这些而不是序列化/反序列化,则可以正确解析单个对象。基本上,长度前缀会限制数据,以便仅读取每个对象的确切数量(而不是读取到文件末尾)。
我强烈建议(作为参数)使用 tag===field-number===1 和 base-128 前缀样式(枚举)。除了使数据在整个过程中完全符合 protobuf(包括前缀数据)之外,这还将使使用额外的辅助方法变得容易:DeserializeItems。这通过迭代器块公开了每个连续的对象,从而可以高效地读取大文件,而无需一次将所有内容都放在内存中。它甚至可以与 LINQ 一起使用。
还有一种方法可以使用 API 选择性地解析/跳过文件中的不同对象 - 例如,跳过前 532 条记录而不处理数据。如果您需要这样的示例,请告诉我。
如果您已经有大量使用 Serialize 而不是 SerializeWithLengthPrefix 存储的数据 - 那么可能仍然可以通过使用 ProtoReader 检测字段编号何时回送来破译数据around :意思是,给定字段“1, 2, 4, 5, 1, 3, 2, 5” - 我们可能可以得出结论,那里有 3 个对象并相应地破译。同样,如果您需要具体示例,请告诉我。
【讨论】:
感谢您的超快速回答 Marc。我不确定我完全理解标签的作用,我应该在 Google 的文档中查找这个,还是这个 p-net 是特定的? 在这里找到我评论的答案:***.com/questions/8601647/…以上是关于如何使用 protobuf-net 读回附加的对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 protobuf-net 反序列化 .asmx webservice 中指定的对象
如何将任意 Ruby 对象保存到磁盘并在必要时将其读回? [关闭]