Angeregt von
diesem Thread heute hab ich mal was kleines probiert. Herausgekommen sind zwei einfache Funktionen, mit denen man von jeder beliebigen Klasse
alle Felder (also
private,
protected,
public und
published) in einer Datei speichern kann. Nichts besonderes, aber man kann doch sehen, dass der Delphi-Compiler auch nur mit Wasser kocht, d.h. Delphi-Objekte sind auch nur Records.
Die beiden Funktionen sind in eine Klasse verpackt, bei der Read-Methode muss das zu übergeben Objekt bereits instanziiert sein. Fehlerabfragen sind nur mangelhaft, ich weiß, aber es ist ja kein Code, der in einem fertigen Programm einsetzbar sein soll, er soll ja nur demonstrativen Zwecken dienen.
Hier ist die
Unit:
Delphi-Quellcode:
unit objectwriter;
interface
uses Sysutils, Classes;
type
TObjectWriter =
class(TObject)
public
procedure Write(o: TObject;
const Filename:
String);
function Read(o: TObject;
const Filename:
String): Boolean;
end;
implementation
{ TObjectWriter }
function TObjectWriter.
Read(o: TObject;
const Filename:
String): Boolean;
var
fs: TFileStream;
size: Integer;
p: Pointer;
begin
Result := False;
//we fill the already created object "o" with the file data
if not FileExists(Filename)
then
Exit;
fs := TFileStream.Create(Filename, fmOpenRead
or fmShareDenyWrite);
try
//check if the filesize matches the instance size
size := o.InstanceSize - 4;
if size <> fs.Size
then
begin
fs.Free;
Exit;
end;
//read the file data
p := Pointer(Integer(o) + 4);
//here begins the class fields
fs.
Read(p^, size);
finally
fs.Free;
end;
end;
procedure TObjectWriter.
Write(o: TObject;
const Filename:
String);
var
fs: TFileStream;
p: Pointer;
size: Integer;
begin
fs := TFileStream.Create(Filename, fmCreate
or fmShareExclusive);
try
size := o.InstanceSize - 4;
//subtract the size of the VMT
p := Pointer(Integer(o) + 4);
//we don't want to save the VMT
fs.
Write(p^, size);
finally
fs.Free;
end;
end;
end.
Der Aufruf erfolgt z.B. so:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
o: TMyClass;
begin
with TObjectWriter.Create do
begin
o := TMyClass.Create;
o.MyField := 5;
ShowMessage(InttoStr(o.FMyField)); //should be "5"
Write(o, 'c:\object.dat');
o.MyField := 6;
ShowMessage(InttoStr(o.FMyField)); //should be "6"
Read(o, 'c:\object.dat');
ShowMessage(InttoStr(o.FMyField)); //should be "5" again
o.Free;
Free;
end;
end;
Infos über den Aufbau von Objekten gibt es z.B.
hier.