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

Posted

技术标签:

【中文标题】如何处理保存和加载文件的不同版本?【英文标题】:How to handle saving and loading different versions of a file? 【发布时间】:2021-08-03 16:34:40 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

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

    文件格式

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

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

    加载器 - 单一文件格式检测器

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

    该函数在检查标识符(和/或文件逻辑)后返回true/false

    加载器 - 单一文件格式

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

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

    管理不同的部分。

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

    加载器 - 多文件格式

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

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

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;
    

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

【讨论】:

以上是关于如何处理保存和加载文件的不同版本?的主要内容,如果未能解决你的问题,请参考以下文章

Akka 如何处理消息版本?

yarn 工作空间如何处理不同版本的外部依赖?

如何处理同一站点的两个版本

Python 的“open()”为“找不到文件”抛出不同的错误——如何处理这两个异常?

如何处理不同的图像尺寸

如何处理具有完全不同构建系统的第三方库?