是否有创建文件格式的正确方法?


12

我正在为使用C#.NET编写的应用程序构建专有文件格式,以存储保存的信息,甚至可能存储项目资源。是否有关于如何执行此操作的标准?我只是将Serialize对象变成二进制文件,然后创建一个标头,该标头将告诉我如何解析文件。这是一个不好的方法吗?


2
我会避免的BinaryFormatter
CodesInChaos

3
无论选择哪种方法(从答案中选择),都始终以格式包含版本号!您的问题已经表明它可能会更改,并且如果必须回溯兼容,版本号将为您节省很多精力。
Jan Doggen

不要忘记正确记录格式
Basile Starynkevitch

Answers:


11

最简单的方法可能是使用XMLSerializer该类将结构序列化为XML 。您可能不需要创建单独的标头和主体结构-而是将所有资产序列化为XML。这使您可以在自己的程序之外轻松检查/编辑文件结构,并且易于管理。

但是,如果您的文件结构真的很复杂,包含许多不同类型的资产,以至于将整个结构序列化为XML太麻烦了,那么您可能会考虑分别序列化每个资产,并使用PackagingC#中的库将它们编译为一个包。。本质上,这就是构造.docx,.xslx,.pptx和其他Office文件格式的方式。


是的,我的项目远不止于此,但是我也试图使它的用户可读性降低,因为我们可能会在许可的上下文中将其部署在字段中。我目前正在使用protobuf-net序列化数据,并且效果很好。但是我必须分别序列化片段,所以您在包装库中所说的听起来像我所需要的。
corylulu

7
亲爱的上帝,不是XML
James

2
@James yeah XML当然也有缺点。在大多数情况下,出于相同的原因,我赞成打包和XML:1.这是一个预先存在的框架,因此需要很少的工作。2.因为它是一个被广泛接受的标准,所以其他系统很容易支持。3.人们很容易检查生成的文件以验证序列化过程。
pswg

XML具有优势,但是由于这些优势,我不喜欢使用XML序列化程序。我相信它要求XML必须采用特定格式。XML是一种半结构化格式,它允许我的文件格式随时间变化,并且仍然向后甚至向前兼容。过去,我编写了自己的XML解析文件,同时注意不要对顺序做任何假设,否则将来将不会有我不知道的标签。如果您可以加载整个XML文件,那么XPATH可能会很好地工作。否则,你留下了一些更复杂的流解析
阿伦

我建议您调查JSON
Basile Starynkevitch

7

对于不得不解析许多文件格式的人来说,我对此有不同的看法。

  • 使幻数非常独特,以便人们使用其他格式的文件格式检测器不会将其误识别为您的。如果使用二进制,请在二进制格式的开头为幻数分配8或16个随机生成的字节。如果使用XML,请在您的域中分配适当的名称空间,以免与其他人发生冲突。如果您使用JSON,请上帝帮您。也许现在有人已经为这种可憎的格式找出了解决方案。

  • 规划向后兼容性。以某种方式存储格式的版本号,以便您的软件的更高版本可以处理差异。

  • 如果文件很大,或者由于某些原因人们可能希望跳过文件的某些部分,请确保有一种不错的方法。XML,JSON和大多数其他文本格式对此特别可怕,因为它们迫使读者即使不关心开头和结尾元素之间的所有数据,也无法对其进行解析。EBML更好一些,因为它存储元素的长度,使您可以一直跳过到最后。如果您采用自定义二进制格式,则存在一种相当普遍的设计,其中将块标识符和长度存储为标题中的第一件事,然后阅读器可以跳过整个块。

  • 将所有字符串存储在UTF-8中。

  • 如果您关心长期可扩展性,请以可变长度形式存储所有整数。

  • 校验和很不错,因为它允许读取器立即中止无效数据,而不是潜在地进入可能产生混乱结果的文件区域。


+1使我意识到我并不是唯一一个认为json是格式可憎的人。
RubberDuck

为什么讨厌json?只需将已知字符串放在已知位置即可识别格式。问题解决了。
Esben Skov Pedersen

它不是完美的,但是它可以与javascript无缝协作,比XML解析速度更快,并且尺寸更小,并且仍然易于阅读。
corylulu

1
“为什么讨厌JSON?” 不支持人类可读的注释,不支持Unicode转义,并且怪异的语法要求我引用键,即使它们从不包含空格。加上通常无法进行扩展,因为没有人考虑过命名空间...到解决该问题时,最终看起来比XML还要糟糕,这一切都是为了避免某种角度的好处括号?
Trejkaz

是的,但是与编程中的所有其他事情一样,使用正确的工具完成任务。在某些应用程序中,XML比JSON更好,反之亦然。
corylulu

4

好吧,有时候您所描述的可能是一个非常糟糕的方法。这是假设当您说“序列化”时,您是在谈论使用语言/框架的能力来简单地获取一个对象并直接输出到某种二进制流。问题是多年来阶级结构发生了变化。如果您所有的类都在较新的类中进行了更改,您是否可以重新加载在以前版本的应用中制作的文件?

为了长期保持文件格式的稳定性,我发现最好稍微卷起袖子,特别是要在类中编写自己的“序列化” /“流化”方法。即,手动处理将值写入流。在陈述状态时写一个标头,描述格式版本,然后按想要的顺序存储要保存的数据。在读取方面,处理文件格式的不同版本变得容易得多。

当然,另一个选择是XML或JSON。对于二进制重载内容,不一定是最大的,但对于人类来说,它是简单易读的……这是长期生存的一大优点。


我正在使用可扩展的protobuf-net(code.google.com/p/protobuf-net)进行序列化。但是,您的观点是正确的,但是,我认为它们是不受此影响的任何文件格式方法。
corylulu

是的,这就是为什么我说有时您只需要动手处理手动写入和加载数据的顺序。
GrandmasterB

我正在构建的应用程序远非动态的,并且对于诸如此类的东西具有太多的价值。
corylulu

1
应用程序越复杂,对文件格式进行非常精细的控制就越重要。请记住,我并不是说每个类都不应该有自己的流式输出……只是您应该为每个类进行控制。然后只需调用这些例程即可。
GrandmasterB

是的,我有适当的方法可以将旧版本升级为现代版本,并且我对类的布局有非常清晰的布局。我对此并不太担心,但是我同意这很重要。我已经为此工作了将近一年,所以我对它的结构如何有一个清晰的认识。
corylulu

1

我也很想听到比我有多年经验的人们对此问题的答案。

我已经为自己的工作实现了几种文件格式,并且已经转向使用XML文件格式。我的需求和与之交互的硬件一直在变化,而且并没有告诉我将来需要在格式中添加什么。XML的主要优点之一是它是半结构化的。出于这个原因,我通常避免使用.NET提供的自动XML序列化,因为我认为它将强制要求使用确切的格式。

我的目标是创建一种XML格式,该格式允许将来添加新的元素和属性,并且使标签的顺序尽可能无关紧要。如果您确定可以将整个文件加载到内存中,那么XPATH可能是一个不错的选择。

如果您正在处理特别大的文件,或者由于其他原因无法一次加载所有文件,则可能只剩下使用XmlStreamReader并扫描已知元素,然后使用ReadSubtree递归到那些元素并再次扫描...


这个答案不是很针对Q,这个站点并不是要成为讨论区,而只是为了进行非推测性的Q&A。您在回答中提出了一些有效的观点,可以用来提出一个关于为什么提问者的方法是好还是不好的建议,但是它不是很集中。请再将您的答案集中在这个问题上,谢谢!
Jimmy Hoffa 2013年

@JimmyHoffa虽然我的回答也支持OP的问题,但我确实清楚地表明了我所建议的XML半结构化方法..但我确实明白你的意思,我可以编辑
Alan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.