版本友好、可扩展的二进制文件格式

12
在我目前所在的项目中,有一个需要将一个相当大的数据结构保存到磁盘上(编辑:考虑到几十兆字节)。作为一个乐观主义者,我认为必定存在针对这类问题的标准解决方案;然而,目前为止我还没有找到满足以下要求的解决方案:
  1. 支持 .NET 2.0,最好是使用 FOSS 实现
  2. 版本友好 (即:如果底层数据结构的更改很简单,比如添加/删除字段,则读取旧版本的格式应该相对简单)
  3. 能够进行某种形式的随机访问,其中部分数据可以在初始创建后进行扩展,而无需反序列化已创建的集合(将其想象成扩展中间结果)
  4. 空间和时间高效(鉴于这一要求,XML 被排除在选项之外)

到目前为止考虑过的选项:

  • XmlSerializer:由于 XML 序列化不满足第 3 和第 4 条要求,因此被排除在外。
  • SerializableAttribute:不支持第 2 和第 3 条要求。
  • Protocol Buffers:据文档所述(关于大数据集),该选项被排除,因为此评论建议在顶部添加另一层,这将要求文件格式本身处理额外的复杂性。
  • HDF5EXI:似乎没有 .NET 实现
  • SQLite/SQL Server Compact edition:手头的数据结构将导致相当复杂的表结构,看起来对于预期的使用过于繁重。
  • BSON:似乎不支持第三个要求。
  • Fast Infoset:似乎只有收费的.NET实现。
  • 非常感谢任何建议或指针。此外,如果您认为上面的信息有误,请提供指针/示例证明我是错误的。


    HDF5确实具有一些.NET支持:http://www.hdfgroup.org/projects/hdf.net/ - Richard Morgan
    @Richard Morgan 到目前为止,我只在 hdfgroup.org 上找到了关于 .NET 的失效链接。谢谢。 - Bas Bossink
    看了一下提供的hdf.net示例,它使用不安全和自定义封送的 .net 概念,感觉不太好。 - Bas Bossink
    是的,我应该强调一下“一些”。 - Richard Morgan
    7个回答

    6

    你考虑过使用 SQL Server Compact Edition吗?

    1. 它有丰富的.NET支持。
    2. 模式的版本控制以及新版本应用程序处理旧模式的能力将完全由您控制。SQL Server Compact的版本控制应该比您的应用程序在旧版本中使用不存在于旧版本中的新功能更加无缝。
    3. 您可以使用大部分SQL语法进行查询。
    4. 显然,从名称上看,这个版本的SQL Server是为嵌入式系统设计的,这可能包括希望避免安装SQL Express或完整版SQL Server的应用程序。

    现在,这将与SQLite具有相同的问题,因为根据您告诉我们的,数据结构可能会变得复杂,但是即使您自己编写二进制格式,这也是正确的。

    顺便说一句,我想到你没有澄清“可观的”究竟是什么意思。如果“可观的”意味着接近或超过4 GB,那么显然SQL Compact将无法工作,其他许多数据库文件格式也无法工作。

    编辑:我注意到您在我的帖子后将SQL Compact Edition添加到了“过于笨重”的列表中。 SQL Compact仅需要5MB的RAM和2MB的磁盘存储空间,具体取决于数据库的大小。因此,问题不能是它太重了。至于第二个点,声称数据结构会非常复杂。如果真的是这样,我怀疑任何关系型数据库产品都是如此,并且自己编写二进制格式将更加复杂。考虑到这一点,您可以查看非关系型数据库产品,例如mongodb

    1
    我认为SQL CE或SQLite是最佳选择。在没有了解当前数据结构的情况下很难提出建议,但嵌入式数据库肯定可以满足所有要求。您还可以获得工具的好处,这些工具允许您直接查询文件中的表/数据(以便进行轻松的调试/测试)。 - Dean Harding
    我同意这个观点。如果你想要高效地随机访问持久化数据,那么你需要一个数据库,可能是关系型或键值对。这正是数据库的用途。它是事实上的标准,似乎满足所有4个要求 - 而SQL CE/SQLite远非“重量级”。 - Aaronaught

    1
    你考虑过(B)JSON吗?如果是这样,那么文档导向的数据库之一可能适合您的需求。CouchDB是一个带有REST API的JSON文档存储库(绝对可以从.Net使用)。CouchDB文档可以具有二进制附件,我曾与将多MB附件存储在文档中而没有问题的人交谈过。我相信MongoDB,这是一种使用二进制JSON作为存储格式的备选文档数据库,也具有.Net绑定。

    这些“NoSQL”替代方案很容易进行版本控制,因为它们本质上是无模式的。JSON非常紧凑,并且它们肯定允许更新现有数据。


    请注意,BSON被列为被丢弃的选项之一,此外我不希望存储二进制大块,而是存储由许多部分组成的.NET数据结构,这些结构可能非常大。 - Bas Bossink
    BJSON是磁盘格式的实现细节。对于这种用途,它非常高效。您肯定可以轻松地扩展或更新MongoDB中的文档,从而消除了您对要求3的排除。您可以将数据结构序列化为MongoDB文档,然后进行查询等操作。任何磁盘存储都是磁盘上的二进制BLOB。这种存储方案或任何其他存储方案都是使与磁盘存储一起工作更加容易的逻辑抽象。我认为您不会找到比文档数据库更好的东西。 - Barry Wark
    我认为像Mongo这样的基于文档的NoSQL数据库会很好地满足要求,并且如果需要的话,还可以获得可扩展性选项作为奖励。 - Brimstedt

    1
    你考虑过类似 db4o 这样的东西吗?许可证可能会有限制,但除此之外它似乎很适合你的需求。

    1

    以下是一个有趣的方案:Cisco 的 ETCH,可在 Apache 许可证下使用(您不需要支付任何版权费用,且您的软件仍然是商业的并归您所有)。

    这个想法是使用 Etch 以二进制形式在您的系统组件之间进行通信。该格式对版本更改具有弹性,并且可以根据您的要求处理丢失的字段等。

    好处在于,您将获得一个更完整的转移系统,建立在二进制格式之上。它被认为非常快速(一台机器每秒执行 900 次 SOAP XML 事务,却能执行 50,000 次 ETCH 事务)。

    如果您需要多个索引,则可以将二进制化的表单存储在轻量级 RDBMS 中。如果只需要一个索引,则简单的键/值存储(如 CouchDB/MongoDB 或分布式环境中的 Cassandra)也将为您提供出色的存储性能!


    0

    你看过二进制序列化吗?

    查看我的这里的帖子获取更多信息。它包含有关如何序列化包含在字典对象中的自定义类的示例代码。不确定你的结构有多复杂,但应该很容易根据你的需求进行调整。

    如果需要更多帮助,请添加评论...


    看到我的最新编辑,我知道二进制/XML序列化,但这两个选项都被否决了。 - Bas Bossink
    好的,但二进制序列化 != XML 序列化。我仍然会检查它。 - GalacticJello

    0
    如果由于空间限制而不能使用XML,您可以通过System.IO.Compression.DeflateStream将XML传输以减小其大小。 Deflate算法本质上与GZip压缩相同,但速度可快达40%(请参见Jeff Atwood's blog)。

    XML不可寻址(没有索引),压缩的流/文件也不可寻址。 - Paul de Vrieze

    0

    不要太快地否认 Protocol Buffers。确实,您提到的手动输入说大约是一兆字节,而您正在处理数十兆字节……但您是否尝试过进行研究以查看此限制是否会影响您?

    如果它仍然对您产生影响,我的建议是采用混合方法:将数据集切成 1MB 大小的块,然后将每个块作为 SQLite 表格的字段存储(作为二进制 blob)。为要索引(或搜索)的元素添加其他字段。

    是的,它增加了复杂性,但似乎没有其他东西能让您接近您想要达到的目标。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接