是否可以仅从序列化数组中反序列化有限数量的项目?
背景:
我有一个流,它包含一个类型为T的序列化数组。该数组可以有数百万个项目,但我想创建内容的预览,只检索前100个项目。我的第一个想法是在输入流周围创建一个限制字节数的包装器,但是没有从数组的项目数到流大小的直接转换。
答案 0 :(得分:1)
不,使用标准.NET序列化无法做到这一点。您必须创建自己的存储格式。例如,包括带有数据块偏移量的标头:
----------------
<magic-value>
<chunks-count>
<chunk-size>
<chunk-1-offset>
<chunk-2-offset> --+
... |
---------------- |
... |
<chunk-1> |
... |
---------------- |
... <-+
<chunk-2>
...
-----------------
...
因此,为了预览数据(来自任意位置),您最多只需加载ceil(required-item-count/chunk-size)
。这会产生一些开销,但它比加载整个文件要好得多。
答案 1 :(得分:1)
什么是序列化器?
使用BinaryFormatter
,这将非常非常棘手。
使用xml,你可以预先处理xml,但这非常棘手。
但是存在其他序列化程序 - 例如,使用protobuf-net,数组/项目列表与单个项目序列之间几乎没有区别 - 因此,选择有限序列的项目非常容易处理整个阵列。
完成protobuf-net示例:
[ProtoContract]
class Test {
[ProtoMember(1)]
public int Foo { get; set; }
[ProtoMember(2)]
public string Bar { get; set; }
static void Main() {
Test[] data = new Test[1000];
for (int i = 0; i < 1000; i++) {
data[i] = new Test { Foo = i, Bar = ":" + i.ToString() };
}
MemoryStream ms = new MemoryStream();
Serializer.Serialize(ms, data);
Console.WriteLine("Pos after writing: " + ms.Position); // 10760
Console.WriteLine("Length: " + ms.Length); // 10760
ms.Position = 0;
foreach (Test foo in Serializer.DeserializeItems<Test>(ms,
PrefixStyle.Base128, Serializer.ListItemTag).Take(100)) {
Console.WriteLine(foo.Foo + "\t" + foo.Bar);
}
Console.WriteLine("Pos after reading: " + ms.Position); // 902
}
}
请注意DeserializeItems<T>
是一个惰性/流式API,所以它只会在迭代时使用流中的数据 - 因此LINQ Take(100)
会避免我们读取整个流。
答案 2 :(得分:0)
您是否可以更改数据源,使其包含另一个数组中的数据预览,您可以单独反序列化?