我有自己用C#编写的数据结构(结构非常复杂)。我需要序列化和反序列化结构。磁盘中序列化文件的大小有时可能非常大(接近1 GB),但也可能很小(基于存储的记录数)。我有以下要求:
我知道这听起来像我需要一个数据库,但由于多种原因我不能使用它。我尝试通过实现ISerializable来实现需求1,这使得它比使用Binary / XML序列化器中内置的.net快得多,但速度不够快。对于要求2是完全难倒我。
那里的任何人对如何解决这个问题都有任何想法?我想任何不得不保存自己的大文件格式的人都必须处理类似的问题。
此致 萨姆
答案 0 :(得分:2)
我没有像你这里那样在任何情况下工作过。但是,我过去曾讨论过类似的问题,这是讨论的结果。 (虽然我承认我从未见过实施)。此外,我担心可能没有任何简单的直接解决方案。
假设:
我。要写入的数据已经过排序。
解决方案:
我。将数据存储分段为多个文件。为每个文件分配一系列排序值。例如。在文件1中记录1-10000,在文件2中记录100001-20000,依此类推。
II。当您编写/读取数据时,您可以预先知道范围,这样您就可以达到第2点。
III。只要两个或多个进程请求完全相同的数据的机会较少,它也将解决第3点。
为了能够提供更准确的解决方案,我们需要有关您要实现的目标的更多信息。
答案 1 :(得分:2)
是数据树,还是完整的图 - 即是否有任何循环引用?如果没有,protobuf-net是一个高性能二进制树序列化器。它支持可枚举项的流式传输(所以你可以跳过记录等 - 而不是缓冲所有内容),但要有效地寻找一个随机元素,我希望你需要某种索引。
单个文件的读/写非常很难;特别是,写入可能需要移动大量的磁盘而不是预期...读取也很棘手,可能需要同步。使用单独的文件会更容易......
跳过早期项目的例子;我可能会添加一个辅助方法,但TryDeserializeWithLengthPrefix
方法将起作用...关键是要观察序列化和反序列化之间我们只创建一个额外的对象。
using System;
using System.IO;
using System.Threading;
using ProtoBuf;
[ProtoContract]
class Foo {
static int count;
public static int ObjectCount { get { return count; } }
public Foo() { // track how many objects have been created...
Interlocked.Increment(ref count);
}
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public double Bar { get; set; }
}
static class Program {
static void Main() {
MemoryStream ms = new MemoryStream();
Random rand = new Random();
for (int i = 1; i <= 5000; i++) {
Foo foo = new Foo { Bar = rand.NextDouble(), Id = i };
Serializer.SerializeWithLengthPrefix(ms, foo,PrefixStyle.Base128, 1);
}
ms.Position = 0;
// skip 1000
int index = 0;
object obj;
Console.WriteLine(Foo.ObjectCount);
Serializer.NonGeneric.TryDeserializeWithLengthPrefix(
ms, PrefixStyle.Base128,
tag => ++index == 1000 ? typeof(Foo) : null, out obj);
Console.WriteLine(Foo.ObjectCount);
Console.WriteLine(((Foo)obj).Id);
}
}
答案 2 :(得分:0)
我认为我们需要更多关于文件实际外观的信息......
你不能只从文件中读取sizeof(yourstruct)的片段,并单独处理它们读取内存中的所有记录吗?
答案 3 :(得分:0)
对于部分(或拆分)反序列化(我一直在看自己,如游戏级别的动态和静态部分),我认为你必须编写自己的序列化引擎。