我正在为使用C#.NET编写的应用程序构建专有文件格式,以存储保存的信息,甚至可能存储项目资源。是否有关于如何执行此操作的标准?我只是将Serialize
对象变成二进制文件,然后创建一个标头,该标头将告诉我如何解析文件。这是一个不好的方法吗?
我正在为使用C#.NET编写的应用程序构建专有文件格式,以存储保存的信息,甚至可能存储项目资源。是否有关于如何执行此操作的标准?我只是将Serialize
对象变成二进制文件,然后创建一个标头,该标头将告诉我如何解析文件。这是一个不好的方法吗?
Answers:
最简单的方法可能是使用XMLSerializer
该类将结构序列化为XML 。您可能不需要创建单独的标头和主体结构-而是将所有资产序列化为XML。这使您可以在自己的程序之外轻松检查/编辑文件结构,并且易于管理。
但是,如果您的文件结构真的很复杂,包含许多不同类型的资产,以至于将整个结构序列化为XML太麻烦了,那么您可能会考虑分别序列化每个资产,并使用Packaging
C#中的库将它们编译为一个包。。本质上,这就是构造.docx,.xslx,.pptx和其他Office文件格式的方式。
protobuf-net
序列化数据,并且效果很好。但是我必须分别序列化片段,所以您在包装库中所说的听起来像我所需要的。
对于不得不解析许多文件格式的人来说,我对此有不同的看法。
使幻数非常独特,以便人们使用其他格式的文件格式检测器不会将其误识别为您的。如果使用二进制,请在二进制格式的开头为幻数分配8或16个随机生成的字节。如果使用XML,请在您的域中分配适当的名称空间,以免与其他人发生冲突。如果您使用JSON,请上帝帮您。也许现在有人已经为这种可憎的格式找出了解决方案。
规划向后兼容性。以某种方式存储格式的版本号,以便您的软件的更高版本可以处理差异。
如果文件很大,或者由于某些原因人们可能希望跳过文件的某些部分,请确保有一种不错的方法。XML,JSON和大多数其他文本格式对此特别可怕,因为它们迫使读者即使不关心开头和结尾元素之间的所有数据,也无法对其进行解析。EBML更好一些,因为它存储元素的长度,使您可以一直跳过到最后。如果您采用自定义二进制格式,则存在一种相当普遍的设计,其中将块标识符和长度存储为标题中的第一件事,然后阅读器可以跳过整个块。
将所有字符串存储在UTF-8中。
如果您关心长期可扩展性,请以可变长度形式存储所有整数。
校验和很不错,因为它允许读取器立即中止无效数据,而不是潜在地进入可能产生混乱结果的文件区域。
好吧,有时候您所描述的可能是一个非常糟糕的方法。这是假设当您说“序列化”时,您是在谈论使用语言/框架的能力来简单地获取一个对象并直接输出到某种二进制流。问题是多年来阶级结构发生了变化。如果您所有的类都在较新的类中进行了更改,您是否可以重新加载在以前版本的应用中制作的文件?
为了长期保持文件格式的稳定性,我发现最好稍微卷起袖子,特别是要在类中编写自己的“序列化” /“流化”方法。即,手动处理将值写入流。在陈述状态时写一个标头,描述格式版本,然后按想要的顺序存储要保存的数据。在读取方面,处理文件格式的不同版本变得容易得多。
当然,另一个选择是XML或JSON。对于二进制重载内容,不一定是最大的,但对于人类来说,它是简单易读的……这是长期生存的一大优点。
我也很想听到比我有多年经验的人们对此问题的答案。
我已经为自己的工作实现了几种文件格式,并且已经转向使用XML文件格式。我的需求和与之交互的硬件一直在变化,而且并没有告诉我将来需要在格式中添加什么。XML的主要优点之一是它是半结构化的。出于这个原因,我通常避免使用.NET提供的自动XML序列化,因为我认为它将强制要求使用确切的格式。
我的目标是创建一种XML格式,该格式允许将来添加新的元素和属性,并且使标签的顺序尽可能无关紧要。如果您确定可以将整个文件加载到内存中,那么XPATH可能是一个不错的选择。
如果您正在处理特别大的文件,或者由于其他原因无法一次加载所有文件,则可能只剩下使用XmlStreamReader并扫描已知元素,然后使用ReadSubtree递归到那些元素并再次扫描...
BinaryFormatter
。