允许不同版本的软件之间的文件向后兼容的最佳设计是什么?


14

有什么好的设计可以允许文件类型在不同版本的软件之间向后兼容?

例如,Microsoft如何将Word 2007、2010和2013等信息获取到所有打开的docx文件,但是不同版本可以保存更多/更少的数据,并以略有不同的方式保存数据,所有数据都保存到相同的文件类型,并且保存在一个版本中的文件可以在另一个版本中打开,但是文件的某些元素可能在较早版本中不可用?

我的意思是,最明显的方法是

private string openfile(string filename)
{
    File.Open(filename)

    ... some logic that gets a header from the file that will never change

    switch (fileversion)
        case 2007:
            .....
        case 2010
            .....
        case 2013
            .....
}

但这似乎是令人难以置信的整体,不是很可扩展,并且可能导致大量复制/粘贴代码。

因此,我正在考虑对所有版本使用基本接口,该接口定义文件中需要存在的不变结构(例如标头)和需要用于序列化/反序列化的方法,然后进行多次继承,以便每个实现该接口的新版本的类继承了旧版本,并且仅覆盖已更改的内容,因为该文件在大多数情况下都是相同的。

我并没有真正为文件的结构而烦恼,因为它已经决定我们将使用XML,并且基本上已经确定了初始模式。但是,毫无疑问,将来会对其进行更改,我只希望能够以一种易于适应这些更改的方式来设计代码。


6
您应该设计文件格式,以便它不仅忽略由于源来自较早版本而丢失的信息,而且还要忽略由于源来自较新版本而导致的意外信息。如果您是从头开始,请同时进行向前兼容性。几乎不需要额外的努力,并且使软件的实用性提高了一倍。
Kilian Foth,2015年

公开时,您是否总是总是预先知道(例如,从标题中)要处理的文件版本?另外,如果要再次提出要求,请检查是否有损坏或恶意文件,不要让它们引起问题。您的系统管理员将感谢您:)。
cxw 2015年

1
是的,版本号将始终位于文件头中,并且头格式将永远不变。我们的想法是,次要软件版本之间创建的文件应该兼容,即可以在v1.2中打开在v1.1中创建的文件,反之亦然,尽管1.1可能缺少1.2中的某些功能,但主要版本将打破向前的兼容性,因此用v2编写的内容不会在v1中打开,但是用v1编写的内容将在v2中打开。
JJBurgess

至于损坏的东西,这些文件包含DSL,打开/关闭它们的程序是一个自定义的内部IDE /编译器。这些不会在生产环境附近出现,因此管理员不必担心。
JJBurgess

Answers:


10

您可能会看看PNG文件格式及其如何处理版本兼容性。每个块都有一个ID,描述它是什么类型的块,并且有一些标志告诉软件,如果它不能理解该ID,该怎么做。例如,“如果您不理解此块,则无法读取文件”,或者“您可以读取文件但不能修改它”,或者“您可以修改文件,但必须删除此块”。为了向后兼容,您的软件只需要处理不存在任何预期数据时的情况。


好点子!PNG格式取决于功能,而不取决于版本。但是,这的确意味着基本格式不得更改。(即定义功能的标题。)
Florian Margaine

那很有意思。我目前正在阅读文件规范。我喜欢批判和辅助块的想法,并可能尝试和努力这英寸
JJBurgess

3

可以通过使用基类和具有基本功能的接口来进行文件处理来实现。然后,对从基类扩展的每个版本使用类,以处理所有特定于版本的情况。如果只有版本特定的实现,则可以更改的功能可以在抽象的基础类中为虚拟的。当您需要一个类来处理文件时,请使用可获取文件处理接口特定于版本的实现的工厂。


我唯一的问题是最终将为每个后续修订版复制特定于版本的实现。假设您有三种基类方法:ReadNames(),ReadAges()和ReadAddresses(),并且在该类的V2中,对ReadAges()进行了更改。如果在V3中,则决定对ReadNames()进行更改,如果所有特定于版本的类都从基类继承,则您将丢失V2更改,或者需要从V2复制/粘贴更改以及到V3实施中
JJBurgess 2015年

1
阅读的实现可以调用不同的类,该类保存有关如何读取此版本的年龄的实际实现。与实际编程相比,使您的课堂成为更多的接口/工厂配置。
同peer

2

我已经用XML完成了它,并且效果很好:

只需允许文档中的任何元素具有任何属性和任何子元素(并且顺序不重要-可以按任何顺序)。从程序的第一个版本开始-读取文档时,请忽略当前版本中不知道的属性和子元素。

将来在将新功能添加到新版本的程序时,请添加属性或子元素。旧版本将忽略它。新版本应检查属性或子元素的压力并进行处理。

例如,您有一些带有文本的项目:

<item text="Hello, world!"/>

在较新的版本中,您想为项目添加颜色,以便添加attribute color

<item text="Hello, world!" color="008000"/>

较旧的版本color在打开文档时只会忽略属性。新版本检查color属性的压力,如果不存在,则分配默认颜色。

通过这种简单的解决方案,您将具有向后和向前的兼容性。


将此作为“简单”选项的一个小问题是,在保存文档时,您将剥离所有意外属性(或使其保持不变)。如其他答案中所述,更好的解决方案至少以某种版本不可知的方式确定是否应删除,保留属性或使文档对于不理解的版本变为只读。
马克·赫德

@Mark Hudr:是的,我无声地假设必须具有向后兼容性,而向前兼容性才是额外的好处。当有人在旧版本的应用程序中打开新文档时,他们保存文件时会丢失一些旧应用程序中不可见的内容,因此不要感到惊讶。在我看来,其他逻辑似乎设计过度。
user3123061 2015年
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.