views:

205

answers:

3

Are there any Delphi serialization libraries that are capable of serializing records and arrays of records instead of classes?

+3  A: 

If you have Delphi 2010, you might want to take a look at DeHL. It contains a serialization library that can handle pretty much any data type.

Mason Wheeler
Just small note, that you can also do (de)serialization of ANY records/dynamic arrays in older Delphi versions too (of course pointers/interfaces/classes won't serialized, there is no such info in RTTI for records/dyn. arrays). I didn't saw any library for it, but made it some time ago. Hint: System.pas - _FinalizeXxx/_InitializeXxx
kibab
+3  A: 

@Max you can use the TJvAppXMLFileStorage component from JEDI to serialize an record or an array of records.

you can use the procedure called WriteBinary to store the data and ReadBinary to read.

unfortunately there is not much documentation on this component, so here you have an very simple example for store a single record (for an array of records you can easily modify this source code).

The record structure

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

Save an record

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;

this procedure create an XML file like this, the data is encoded in an hexadecimal format.

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

Read the persisted data

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;

Check this full project (tested in 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.
RRUZ
84030000000000003333333333331F400D737472696E6720746573742031000000000000000D737472696E672074657374203200000000000000000000000000 maybe contains an Integer, a Double and two string[20], maybe not :) - Why not use a data transfer object to serialize to a real XML file, which is typesafe and supports versioning / compatibility, and also adds an "anti-corruption layer"?
mjustin
Binary content to XML. A perfect $$$$-storm of bad design decisions. Skip the XML if you're going to go binary.
Warren P
+1  A: 

Being a record, if you don't have properties, I don't believe you're any further ahead, trying to use any of the persistence frameworks (like DeHL).

The accepted answer, while technically correct, is dubious in real-world utility, and has many long term support-nightmare scenarios if you use it in production. DON'T DO IT.

If your program is just a bit of ad-hoc'ery, may I humbly suggest that you rock it old-school with a "file of record", a classic Turbo Pascal technique that still works.

Warren P
@Warren, what do you mean with "is dubious in real-world utility"? any examples?
RRUZ
@Warren: Unfortunately file types do not support arrays. BTW the code that uses serialization does not go into production. This is just for the debugging. In particular I'm saving the result of the lengthy calculation, so I can load these results and start debugging a little faster. But it's a good tip, thanks. +1
Max
Good to know that you know. You know?
Warren P