Delphi (win32)序列化库

5
有没有 Delphi 序列化库可以序列化记录和记录数组而不是类?
4个回答

6

@Max,你可以使用JEDITJvAppXMLFileStorage组件来序列化一条记录或一组记录。

你可以使用名为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.

2
84030000000000003333333333331F400D737472696E6720746573742031000000000000000D737472696E672074657374203200000000000000000000000000 可能包含一个整型、一个双精度浮点数和两个长度为20的字符串,也可能不包含 :) - 为什么不使用数据传输对象将其序列化为真正的XML文件呢?这样做是类型安全的,支持版本控制/兼容性,并且添加了"反腐层"。 - mjn
1
将二进制内容转换为XML。这是一场造成了设计灾难的完美风暴。如果你要使用二进制,就不需要使用XML。 - Warren P
@Warren XML增加了一种标准的方式来分离二进制数据,并且还可以包含属性等元数据。它在结构变化方面非常强大,同时也很容易阅读(如果元素名称具有自我说明的名称)。 - mjn
最好编写基于RTTI的记录持久化层,将XML或JSON输出并跳过二进制。我们传输的不是图片,而是一些整数和其他标量和字符串类型。 - Warren P

3
如果您使用的是Delphi 2010,您可能需要查看DeHL。它包含一个序列化库,可以处理几乎所有数据类型。

只是一个小提示,您也可以在旧版的Delphi中对任何记录/动态数组进行(反)序列化(当然指针/接口/类不会被序列化,因为RTTI中没有这样的信息)。我之前做过这个,但没有看到任何相关的库。提示:System.pas - _FinalizeXxx/_InitializeXxx。 - Krystian Bigaj

3

另外一个解决方案可以在Delphi 5到XE2之间使用,可以在我们的一个开源单元中找到。

实际上,它实现了以下功能:

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

序列化使用优化的二进制格式,并能够将任何记录或动态数组保存和加载为RawByteString。你还可以使用JSON序列化,包括自定义布局 - 参见记录的自定义JSON序列化


更新:当前版本的库将使用自Delphi 2010以来可用的增强型RTTI来序列化JSON记录和动态数组内容。请参见http://blog.synopse.info/post/2014/05/18/Automatic-JSON-serialization-of-record-or-dynamic-arrays-via-Enhanced-RTTI。该库仍在大力维护,并在Win32和Win64平台上测试了XE6。对于旧版本的Delphi,您可以将记录定义为纯文本,因为标准RTTI提供的信息不足够。 - Arnaud Bouchez

0

作为一条记录,如果你没有属性,我不认为你会更进一步,尝试使用任何持久性框架(如DeHL)。

虽然技术上正确,但接受的答案在现实世界中的效用是可疑的,并且如果您在生产中使用它,会有许多长期支持噩梦的情况。不要这样做。

如果您的程序只是一些特定的需求,我谨虔地建议您使用“文件记录”,这是一种经典的Turbo Pascal技术,仍然有效。


“is dubious in real-world utility”是什么意思?有什么例子吗? - RRUZ
很遗憾,文件类型不支持数组。顺便说一下,使用序列化的代码不会进入生产环境。这只是为了调试。特别是我正在保存漫长计算的结果,以便可以加载这些结果并更快地开始调试。但这是一个好建议,谢谢。+1 - Max
将二进制数据存储在XML中与直接使用“File Of Record”老式方法或将记录二进制写入流的简单方法相比,没有任何优势,并且存在许多实际的缺点。 - Warren P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接