【问题标题】:Delphi (win32) serialization librariesDelphi (win32) 序列化库
【发布时间】:2010-06-06 13:38:25
【问题描述】:

是否有任何 Delphi 序列化库能够序列化记录和记录数组而不是类?

【问题讨论】:

    标签: delphi serialization


    【解决方案1】:

    @Max 你可以使用JEDI 中的TJvAppXMLFileStorage 组件来序列化一条记录或一组记录。

    您可以使用名为WriteBinary 的过程来存储数据并使用ReadBinary 来读取数据。

    不幸的是,关于这个组件的文档不多,所以这里有一个非常简单的示例来存储单个记录(对于记录数组,您可以轻松修改此源代码)。

    记录结构

    type
      MyRecord= record
          Field1 : Integer;
          Field2 : Double;
          Field3 : String[20];
          Field4 : String[20];
      end;
    

    保存记录

    Procedure SaveMyRecord(Rec : MyRecord);
    var
      MyStore: TJvAppXMLFileStorage;
    begin
      MyStore:= TJvAppXMLFileStorage.Create(nil);
      try
        MyStore.FileName:='C:\temp\record.xml'; 
        //this component supports store multiples objects to the same file, so you need use an identifier for you particular object, in this case i'm use the Dummy name.
        MyStore.WriteBinary('Dummy', @Rec,sizeof(Rec));
        MyStore.Xml.SaveToFile(MyStore.FileName);
      finally
        MyStore.Free;
      end;
    end;
    

    这个程序创建一个像这样的XML文件,数据以十六进制格式编码。

    <?xml version="1.0" encoding="iso-8859-1"?>
    <Configuration>
      <Dummy>84030000000000003333333333331F400D737472696E6720746573742031000000000000000D737472696E672074657374203200000000000000000000000000</Dummy>
    </Configuration>
    

    读取持久化数据

    Procedure LoadMyRecord(var Rec : MyRecord);
    var
      MyStore: TJvAppXMLFileStorage;
    begin
      MyStore:= TJvAppXMLFileStorage.Create(nil);
      try
        MyStore.FileName:='C:\temp\record.xml';//point to the same file
        MyStore.Xml.LoadFromFile(MyStore.FileName); //load the file
        MyStore.ReadBinary('Dummy', @Rec,sizeof(Rec));//use the Dummy identifier and pass the record as an pointer
      finally
        MyStore.Free;
      end;
    end;
    

    检查这个完整的项目(在 Delphi 7 中测试)

    program ProjectPersistRecord;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      JvAppXMLStorage;
    
    type
      MyRecord= record
          Field1 : Integer;
          Field2 : Double;
          Field3 : String[20];
          Field4 : String[20];
      end;
    
    Procedure SaveMyRecord(Rec : MyRecord);
    var
      MyStore: TJvAppXMLFileStorage;
    begin
      MyStore:= TJvAppXMLFileStorage.Create(nil);
      try
        MyStore.FileName:='C:\temp\record.xml';
        MyStore.WriteBinary('Dummy', @Rec,sizeof(Rec));
        MyStore.Xml.SaveToFile(MyStore.FileName);
      finally
        MyStore.Free;
      end;
    end;
    
    Procedure LoadMyRecord(var Rec : MyRecord);
    var
      MyStore: TJvAppXMLFileStorage;
    begin
      MyStore:= TJvAppXMLFileStorage.Create(nil);
      try
        MyStore.FileName:='C:\temp\record.xml';
        MyStore.Xml.LoadFromFile(MyStore.FileName);
        MyStore.ReadBinary('Dummy', @Rec,sizeof(Rec));
      finally
        MyStore.Free;
      end;
    end;
    
    
    Var
        Rec :  MyRecord;
    begin
      //Fill the record
      Rec.Field1:=900;
      Rec.Field2:=7.8;
      Rec.Field3:='string test 1';
      Rec.Field4:='string test 2';
      SaveMyRecord(Rec); //save the record
      FillChar(Rec,SizeOf(Rec),#0); //clear the record variable
      LoadMyRecord(Rec);//restire the record data
      //show the loaded data
      Writeln(rec.field1);
      Writeln(rec.field2);
      Writeln(rec.field3);
      Writeln(rec.field4);
      Readln;
    end.
    

    【讨论】:

    • 84030000000000003333333333331F400D737472696E6720746573742031000000000000000D737472696E672074657374203200000000000000000000000000也许包含一个整数,双精度和两个串[20],也许不是:) - 为什么不使用的数据传输对象序列化到一个真正的XML文件,它是类型安全和支持版本/兼容性,还增加了“反腐层”?
    • 二进制内容到 XML。一场完美的 $$$- 糟糕设计决策的风暴。如果您要使用二进制文件,请跳过 XML。
    • @Warren XML 增加了使用标准方法分离二进制数据的便利性,并且还可能包含属性等元数据。它在结构变化和人类可读性方面非常健壮(如果元素名称具有自记录名称)
    • 最好编写一个基于 RTTI 的 Record-persistence 层,将 XML 或 JSON 写出并在此处跳过二进制文件。这不是我们要传输的图片,它是一些整数和其他标量和字符串类型。
    【解决方案2】:

    如果你有 Delphi 2010,你可能想看看DeHL。它包含一个序列化库,可以处理几乎任何数据类型。

    【讨论】:

    • 请注意,您也可以在旧的 Delphi 版本中对任何记录/动态数组进行(反)序列化(当然指针/接口/类不会序列化,没有这样的信息在 RTTI 中用于记录/动态数组)。我没有看到任何图书馆,但前一段时间做了。提示:System.pas - _FinalizeXxx/_InitializeXxx
    【解决方案3】:

    另一个解决方案,从 Delphi 5 到 XE2,可用in one of our OpenSource unit

    其实它实现了:

    • 一些用于处理记录类型的低级 RTTI 函数:RecordEquals, RecordSave, RecordSaveLength, RecordLoad;
    • 专用的TDynArray 对象,它是任何动态数组的包装器,能够在任何动态数组周围公开类似TList 的方法,甚至包含记录、字符串或其他动态数组。它能够序列化任何动态数组。

    序列化使用优化的二进制格式,并且能够以RawByteString 保存和加载任何记录或动态数组。您还有 JSON 序列化,包括自定义布局 - 请参阅 sustom JSON serialization of records

    【讨论】:

    • 更新:该库的当前版本将使用自 Delphi 2010 以来可用的增强型 RTTI 序列化为 JSON 记录和动态数组内容。请参阅blog.synopse.info/post/2014/05/18/… 并且该库仍然得到大量维护,并在 Win32 和 Win64 平台上使用 XE6 进行了测试。对于旧版本的 Delphi,您可以将记录定义为纯文本,因为标准 RTTI 没有提供足够的信息。
    【解决方案4】:

    作为一个记录,如果你没有属性,我不相信你会走得更远,尝试使用任何持久性框架(如 DeHL)。

    公认的答案虽然在技术上是正确的,但在现实世界的实用程序中是可疑的,并且如果您在生产环境中使用它,它会有许多长期支持——噩梦般的场景。不要这样做。

    如果您的程序只是一个临时性的程序,我可以谦虚地建议您使用“记录文件”(一种仍然有效的经典 Turbo Pascal 技术)来使用老式的方法。

    【讨论】:

    • “在现实世界的实用程序中可疑”是什么意思?有什么例子吗?
    • 不幸的是文件类型不支持数组。顺便说一句,使用序列化的代码不会投入生产。这只是为了调试。特别是我保存了冗长计算的结果,因此我可以加载这些结果并更快地开始调试。但这是一个很好的提示,谢谢。 +1
    • 在 XML 中存储二进制数据没有任何优势,而且与使用 File Of Record old-school 或简单的记录二进制写入到流直接存储二进制数据相比,存在许多真正的缺点.
    猜你喜欢
    • 2010-10-14
    • 2010-09-09
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多