如何处理保存和加载文件的不同版本?

How to handle saving and loading different versions of a file?

在制作一个以特定格式保存文件的应用程序时,将来会添加或不同的功能,要求保存的文件具有不同的格式,是否有任何技术可用于处理这种“版本控制”?

我有兴趣阅读其中的一些解释如何加载由不同版本的应用程序创建的已保存文件的所有可能格式。

我目前的想法是在保存的文件中保存一个版本指示器,并为每个具有自己格式的“版本”使用不同的加载函数,试图将它们与最新版本应用程序的当前功能联系起来.

这主要是基于意见,所以请这样处理...以下是我对该主题的见解:

  1. 文件格式

    您应该有 2 个标识符。一个用于 文件格式 有时称为幻数,第二个用于 版本 。两者都应位于文件开头的某个位置,并且通常编码为 ASCII,因此您可以使用记事本或其他任何工具轻松检查它们。

    让数据块拥有自己的类型和版本标识符是个好主意。

  2. loader - 单一文件格式检测器

    我用它来检查特定的文件格式。输入是数组(小的通常为 1Kbyte),包含文件的第一个字节、数组大小和文件大小。该函数检查文件是否是某种类型的有效文件。这用于自动检测文件格式而不是中继文件扩展名(Windows 和低等级用户的必要性,因为他们经常破坏文件扩展名)

    函数returns true/false 检查标识符(和/或文件逻辑)后

  3. loader - 单一文件格式

    这会将文件加载到您的应用程序中。对于多版本,您有 2 个选项。每个版本都有单独的代码,或者一个函数用 if 语句分区,如下所示:

    if (version==???) ... 
    if (version>=???) ... else ...
    if ((version>=???)&&(version<???)) ...
    

    管理不同的部分。

    我更喜欢分区代码方法,因为它通常代码更少且更易于管理,因为不同的版本通常只添加一些小的更改并且大部分代码状态相同。

  4. loader - 多文件格式

    只需将文件的第一个字节加载到内存中,然后使用 #2 中的函数检查所有支持的文件格式。成功检测到文件格式后,使用 #3 的加载程序函数加载文件。如果未检测到文件格式,则使用文件扩展名...

这里是来自我的 SVG 加载程序的 #4 的简单 C++/VCL 示例 class:

bool decode_interface_class::load(AnsiString name)
    {
    int hnd=-1;
    int siz=0,siz0=0;
    BYTE *dat=NULL;
    reset();
    #ifdef decode_interface_log
    decode_id.num=0;
    decode_log="";
    #endif
    decode_cfg =true;
    decode_col =true;
    decode_tool=true;
    decode_ext=ExtractFileExt(name).LowerCase();
    decoded_ext=".";
    decoded_info="";

    decode_emf emf;
    decode_wmf wmf;
    decode_dkr dkr;
    decode_dk3 dk3;
    decode_box box;
    decode_bxl bxl;
    decode_dxf dxf;
    decode_svg svg;
    decode_v2x v2x;
    decode_v2d v2d;

    const int _size=4096;
    BYTE head[_size];
    #ifdef decode_interface_log
    siz=0;  // find minimal size
    if (siz<_decode_emf_hdr) siz=_decode_emf_hdr;
    if (siz<_decode_wmf_hdr) siz=_decode_wmf_hdr;
    if (siz<_decode_dkr_hdr) siz=_decode_dkr_hdr;
    if (siz<_decode_dk3_hdr) siz=_decode_dk3_hdr;
    if (siz<_decode_box_hdr) siz=_decode_box_hdr;
    if (siz<_decode_bxl_hdr) siz=_decode_bxl_hdr;
    if (siz<_decode_dxf_hdr) siz=_decode_dxf_hdr;
    if (siz<_decode_svg_hdr) siz=_decode_svg_hdr;
    if (siz<_decode_v2x_hdr) siz=_decode_v2x_hdr;
    if (siz<_decode_v2d_hdr) siz=_decode_v2d_hdr;
    if (siz>_size)
        {
        decode_log+="Decoding header size too small needed to be "+AnsiString(siz)+" Bytes.\r\n";
        }
    #endif


    hnd=FileOpen(name,fmOpenRead);
    if (hnd<0)
        {
        #ifdef decode_interface_log
        decode_log+="File "+name+" not found.\r\n";
        #endif
        return false;
        }
    siz=FileSeek(hnd,0,2);
        FileSeek(hnd,0,0);
    dat=new BYTE[siz];
    if (dat==NULL)
        {
        #ifdef decode_interface_log
        decode_log+="Not enough memory need: "+AnsiString(siz)+" Bytes.\r\n";
        #endif
        FileClose(hnd);
        return false;
        }
    siz0=siz;
    siz=FileRead(hnd,dat,siz);
    FileClose(hnd);
    if (siz!=siz0)
        {
        #ifdef decode_interface_log
        decode_log+="Disc drive or file system error.\r\n";
        #endif
        }

    this[0].filename=name;

    // file signature detection
    for (int i=0;i<_size;i++) if (i<siz) head[i]=dat[i]; else head[i]=0;
         if (emf.is_header(head,_size,siz)) { decoded_ext=_decode_emf_ext; emf.load(this[0],dat,siz); }
    else if (wmf.is_header(head,_size,siz)) { decoded_ext=_decode_wmf_ext; wmf.load(this[0],dat,siz); }
    else if (dkr.is_header(head,_size,siz)) { decoded_ext=_decode_dkr_ext; dkr.load(this[0],dat,siz); }
    else if (dk3.is_header(head,_size,siz)) { decoded_ext=_decode_dk3_ext; dk3.load(this[0],dat,siz); }
    else if (box.is_header(head,_size,siz)) { decoded_ext=_decode_box_ext; box.load(this[0],dat,siz); }
    else if (bxl.is_header(head,_size,siz)) { decoded_ext=_decode_bxl_ext; bxl.load(this[0],dat,siz); }
    else if (dxf.is_header(head,_size,siz)) { decoded_ext=_decode_dxf_ext; dxf.load(this[0],dat,siz); }
    else if (svg.is_header(head,_size,siz)) { decoded_ext=_decode_svg_ext; svg.load(this[0],dat,siz); }
    else if (v2x.is_header(head,_size,siz)) { decoded_ext=_decode_v2x_ext; v2x.load(this[0],dat,siz); }
    else if (v2d.is_header(head,_size,siz)) { decoded_ext=_decode_v2d_ext; v2d.load(this[0],dat,siz); }
    // if fail use file extension
    else if (decode_ext==_decode_emf_ext)   { decoded_ext=_decode_emf_ext; emf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_wmf_ext)   { decoded_ext=_decode_wmf_ext; wmf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_dkr_ext)   { decoded_ext=_decode_dkr_ext; dkr.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_dk3_ext)   { decoded_ext=_decode_dk3_ext; dk3.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_box_ext)   { decoded_ext=_decode_box_ext; box.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_bxl_ext)   { decoded_ext=_decode_bxl_ext; bxl.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_dxf_ext)   { decoded_ext=_decode_dxf_ext; dxf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_svg_ext)   { decoded_ext=_decode_svg_ext; svg.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_v2x_ext)   { decoded_ext=_decode_v2x_ext; v2x.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    else if (decode_ext==_decode_v2d_ext)   { decoded_ext=_decode_v2d_ext; v2d.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
    // if fail then error
    else{
        #ifdef decode_interface_log
        decode_log+="File "+name+" not recognized.\r\n";
        #endif
        }
    if (decode_cfg)
        {
        if (!decode_col )
            {
            if (decode_tool) set_cfgs  (dk3_charaktool ,33);
                             set_colors(dk3_charakcolor,33);
            }
        if (!decode_tool)    set_tools (dk3_charaktool ,33);
        }
    #ifdef decode_interface_log
    if (decode_ext!=decoded_ext)
        decode_log+="Wrong file extension in "+name+" should be \""+decoded_ext+"\"\r\n";
    hnd=FileCreate(ExtractFilePath(Application->ExeName)+"svg_decode.log");
    FileWrite(hnd,decode_log.c_str(),decode_log.Length());
    FileClose(hnd);
    #endif
    compute();
    compute_objsize();
    if (dat) delete[] dat;
    return true;
    }

每个文件格式都定义了其 header 大小 _decode_???_hdr 字节和默认文件扩展名 _decode_??_ext 用于检测文件格式。函数 ???.is_header(...)#2???.load(...)#3。我使用从内存加载而不是直接文件访问,因为它更适合我的需要。但是这对于太大的文件来说并不方便。