Saving a TObject to a File
Asked Answered
H

7

11

How can one save an Object, in its current state, to a file? So that it can immediately be read and restored with all its variables.

Heimdall answered 30/3, 2009 at 18:47 Comment(2)
Wikipedia says: "The set of values of the attributes of a particular object is called its state." Delphi actually has no built-in mechanism to save the full object state regardless of visibility, only published properties are supported. RTTI should be extended to optionally include all fields IMHO.Beebeebe
Is this situation updated?Balalaika
B
4

What you are looking for is called object persistance. This article might help, and there are many others if you google for "delphi persisting objects".

Birdseed answered 30/3, 2009 at 18:54 Comment(2)
Probably the man used Google which pointed him to Stackoverflow. "Ask Google" is not a real answer. Francois answer's instead is a REAL (and useful) answer.Brasher
Nice (and obvious) solution, but its practicality is limited. The OP asked to save an object. Your solution will not work for TObject.Brasher
B
3

If you descend your object from TComponent, you can use some built-in functionality to stream the object to a file. I think this only works well for simple objects.

Some sample code to get you started:

unit Unit1;

interface

uses
  Classes;

type
  TMyClass = class(TComponent)
  private
    FMyInteger: integer;
    FMyBool: boolean;
    FMyString: string;
  public
    procedure ToFile(AFileName: string);
  published
    property MyInteger: integer read FMyInteger write FMyInteger;
    property MyString: string read FMyString write FMyString;
    property MyBool: boolean read FMyBool write FMyBool;
  end;

implementation

{ TMyClass }

procedure TMyClass.ToFile(AFileName: string);
var
  MyStream: TFileStream;
begin
  MyStream := TFileStream.Create(AFileName);
  try
    Mystream.WriteComponent(Self);
  finally
    MyStream.Free;
  end;
end;

end.
Boltonia answered 30/3, 2009 at 19:28 Comment(1)
Nice (and obvious) solution, but its practicality is limited. The OP asked to save an object.Brasher
J
3

As already stated, the easiest way is to use a Stream and its WriteComponent and ReadComponent methods.
But be aware that :
- it works for descendants of TComponent, not plain TObject;
- only for the published properties (those saved in a dfm), not the public ones nor (a fortiori) the privwte ones;
- you have to pay a special attention for the Name property when restoring the component.

You may find some code you could use in these SO answers: Replace visual component at runtime in Delphi, Duplicating components at Run-Time

Joint answered 30/3, 2009 at 19:57 Comment(1)
Nice (and obvious) solution, but its practicality is limited. The OP asked to save an object.Brasher
W
2

There's also a roll-your-own XML method here on S.O.

Wait answered 30/3, 2009 at 19:5 Comment(0)
B
2

Solution 1. You can use JVCL TJvAppXMLFileStorage (see code below). But JVCL is huge!! You have to consider twice if you want or not, to drag such a huge dependency after you, your whole life.

Solution 2. Save your object to a binary file (my preferred solution). Believe me, it is not that hard. Use the ccStreamMem.pas, or even better the ccStreamBuff.pas (buffered writing) in my LightSaber Core library.
You have some code examples on how to do it, in Delphi in all its glory book.
PS: LightSaber is a lightweight alternative to JVCL.

Here is an example of how to save a record to a binary file. The operation is identical for TObject!

// Supposing you have a record (could be also an object) called RAnimationParams that you want to save to disk:

INTERFACE

USES
  System.SysUtils, Vcl.Graphics, ccStreamBuff;

TYPE
  TFrameDelayType = (fdAuto, fdUser);

  RAnimationParams = record
    Color         : TColor;          
    DelayType     : TFrameDelayType;
    procedure WriteToStream (IOStream: TCubicBuffStream);
    procedure ReadFromStream(IOStream: TCubicBuffStream);
  end;

IMPLEMENTATION

procedure RAnimationParams.WriteToStream(IOStream: TCubicBuffStream);
begin
 IOStream.WriteByte    (Ord(DelayType));
 IOStream.WriteInteger (Color);
 IOStream.WritePadding (32);
end;

procedure RAnimationParams.ReadFromStream(IOStream: TCubicBuffStream);
begin
 DelayType    := TFrameDelayType(IOStream.ReadByte);
 Color        := IOStream.ReadInteger;
 IOStream.ReadPadding (32);
end;

The padding at the end allows you to change your record/object structure later, without changing the format of your binary file.

To actually save the RAnimationParams to disk you just do:

MyBinFile:= TCubicBuffStream.CreateRead('C:\Test.bin');
AnimationParams.WriteToStream(MyBinFile);
MyBinFile.Free;

Same code when you want to load the RAnimationParams back from Test.bin, but you use CreateWrite instead of CreateRead.

The TCubicBuffStream class has even dedicated functions such as ReadHeader/CreateWrite that allow you to easily add "file magic numbers" and "file version numbers" to your binary files.

See? Not so difficult. And it will work for any object, not only for TComponent.


Example for JVCL, but it won't work for TObject but only for persistent derivates:

 uses
      JvAppXMLStorage;
    
    var
      Storage: TJvAppXMLFileStorage;
    begin
      Storage := TJvAppXMLFileStorage.Create(nil);
      try
        Storage.WritePersistent('', MyObject);
        Storage.Xml.SaveToFile('S:\TestFiles\Test.xml');
        Storage.Xml.LoadFromFile('S:\TestFiles\Test.xml');
        Storage.ReadPersistent('', MyObject);
      finally
        Storage.Free;
      end;
    end;
Brasher answered 13/4, 2009 at 12:10 Comment(1)
E2010 Incompatible types: 'TPersistent' and 'TSomething.TElse<TYetAnother>'Norenenorfleet
J
1

There is a good tutorial here. Keep in mind that you have to have RTTI (run time type information) to save an object at run-time using this approach, so it will only capture published properties of a class.

Jadejaded answered 30/3, 2009 at 19:4 Comment(0)
W
-1

You've already gotten some good answers to your question. Depending on what you're actually doing, it might be desirable to use a pre-built library or component to save objects. This is an inexpensive and nifty library/component set that makes it trivial to persist and restore objects, and pretty easily (i.e., with a little bit of code) accommodates persisting even unpublished members of an object: http://www.deepsoftware.ru/rsllib/index.html Not something that's rocket science, but if you're doing a lot of this sort of thing this component provides a nice framework for it.

Developer Express also includes a general purpose cxPropertiesStore component as part of the ExpressEditors library that comes with some of their components.

Witty answered 30/3, 2009 at 22:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.