我有大约5亿件物品的清单。如果我序列化单个项目而不是列表,我可以将它序列化为带有protobuf-net文件的文件 - 我无法将项目收集到价格列表中,然后序列化,因为我的内存不足。所以,我必须一次序列化一条记录:
using (var input = File.OpenText("..."))
using (var output = new FileStream("...", FileMode.Create, FileAccess.Write))
{
string line = "";
while ((line = input.ReadLine()) != null)
{
Price price = new Price();
(code that parses input into a Price record)
Serializer.Serialize(output, price);
}
}
我的问题是关于反序列化部分。似乎Deserialize方法不会将流的位置移动到下一条记录。我试过了:
using (var input = new FileStream("...", FileMode.Open, FileAccess.Read))
{
Price price = null;
while ((price = Serializer.Deserialize<Price>(input)) != null)
{
}
}
我看到一个真实的价格记录,然后其余的是空记录 - 我得到Price对象,但所有字段都被初始化为默认值。
如何正确反序列化包含未序列化为列表的对象列表的流?
答案 0 :(得分:4)
IEnumerable<T>
一起使用的SerializeItems和DeserializeItems方法,允许流入和流出。最简单的方法是通过源数据的“迭代器块”来为它提供枚举。
如果出于某种原因,这是不方便的,那就是在每个项目的基础上使用SerializeWithLengthPrefix和DeserializeWithLengthPrefix 100%相同,指定(作为参数)字段:1和prefix-style:base-128。您甚至可以使用SerializeWithLengthPrefix进行写入,并使用DeserializeItems进行读取(只要使用字段1和base-128)。
重新举例 - id必须在完全可重现的场景中看到评论;实际上,我会期望,只有一个对象退出,包含每个对象的组合值 - 因为没有长度前缀,protobuf规范假定你只是连接值到单个对象。上面提到的两种方法避免了这个问题。
答案 1 :(得分:2)
可能是我为时已晚......但只是为了补充Marc已经说过的话。
当您使用Serializer.Serialize(output, price);
protobuf将连续消息视为(相同)单个对象的一部分时。因此,当您使用
while ((price = Serializer.Deserialize<Price>(input)) != null)
您将获得所有记录。因此,您只会看到最后的价格记录。
要执行您要执行的操作,请将序列化代码更改为:
Serializer.SerializeWithLengthPrefix(output, price, PrefixStyle.Base128, 1);
和
while ((price = Serializer.DeserializeWithLengthPrefix<Price>(input, PrefixStyle.Base128, 1)) != null)
答案 2 :(得分:0)
自Marc回答以来,API显然发生了变化 似乎没有SerializeItems方法了。
以下是一些应该有帮助的最新信息:
ProtoBuf.Serializer.Serialize(stream, items);
如上所示,可以采用IEnumerable,它在序列化时可以完成工作
然而,有一个DeserializeItems(...)方法和魔鬼在细节:)
如果像上面那样序列化IEnumerable,那么你需要调用DeserializeItems传递PrefixStyle.Base128和1作为fieldNumber,因为这些是默认值。
这是一个例子:
ProtoBuf.Serializer.DeserializeItems<T>(stream, ProtoBuf.PrefixStyle.Base128, 1));
另外正如Marc和Vic指出的那样,您可以像这样对每个项目进行序列化/反序列化(使用PrefixStyle和fieldNumber的自定义值):
ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, item, ProtoBuf.PrefixStyle.Base128, fieldNumber: 1);
和
T item;
while ((item = ProtoBuf.Serializer.DeserializeWithLengthPrefix<T>(stream, ProtoBuf.PrefixStyle.Base128, fieldNumber: 1)) != null)
{
// do stuff here
}