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.
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".
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.
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
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;
E2010 Incompatible types: 'TPersistent' and 'TSomething.TElse<TYetAnother>'
–
Norenenorfleet 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.
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.
© 2022 - 2024 — McMap. All rights reserved.