Forum > General
saving and loading a changing record
pyros:
Hello,
Within my application, I would like to save the users data to a file, and load it later.
My idea is to put everything that is going to be saved into one big record and write it.
When I add or remove any feature, the size and layout of the record will change.
When a file is loaded, I would like it to only write the fields of the records that match
those that existed when it was saved.
i.e. user saves record with: title, height, width, color, levels
user loads into record with: title, height, width, depth, shape, levels
so: title, height & levels will be overwritten, depth & shape will not.
I was thinking this may work with XML, but I have no idea how.
XMLPropStorage does something like this with a form, but not a record.
Any hints or suggestions would be welcome!
P.
Leledumbo:
--- Quote ---XMLPropStorage does something like this with a form, but not a record.
--- End quote ---
Correction: it does that with a form automatically, but nothing stops you from using it to save & load other values. Implement OnSaveProperties and OnRestoreProperties with your record values. Here's a code fragment from one of my projects:
--- Code: ---var
CompTune: record
LZMA, Force, Brute, UltraBrute: Boolean;
end;
Overlay: (olCopy, olStrip, olSkip);
Additional: record
AllMethods, AllFilters: Boolean;
end;
Other: record
KeepBackup, SaveAsDef: Boolean;
end;
UPXThreadCount: Byte;
...
procedure TMainForm.UserPrefsRestoreProperties(Sender: TObject);
begin
with UserPrefs do begin
IniSection := 'AdvancedOpts';
with CompTune do begin
LZMA := ReadBoolean('LZMA', False);
Force := ReadBoolean('Force', False);
Brute := ReadBoolean('Brute', False);
UltraBrute := ReadBoolean('UltraBrute', False);
end;
Ord(Overlay) := ReadInteger('Overlay', 0);
with Additional do begin
AllMethods := ReadBoolean('AllMethods', False);
AllFilters := ReadBoolean('AllFilters', False);
end;
with Other do begin
KeepBackup := ReadBoolean('KeepBackup', False);
SaveAsDef := ReadBoolean('SaveAsDefault', False);
end;
UPXThreadCount := ReadInteger('ThreadCount', 1);
IniSection := 'Preferences';
end;
TrackCompLvlChange(nil);
end;
procedure TMainForm.UserPrefsSaveProperties(Sender: TObject);
begin
UserPrefs.IniSection := 'AdvancedOpts';
if Other.SaveAsDef then
with UserPrefs do begin
with CompTune do begin
WriteBoolean('LZMA', LZMA);
WriteBoolean('Force', Force);
WriteBoolean('Brute', Brute);
WriteBoolean('UltraBrute', UltraBrute);
end;
WriteInteger('Overlay', Ord(Overlay));
with Additional do begin
WriteBoolean('AllMethods', AllMethods);
WriteBoolean('AllFilters', AllFilters);
end;
WriteBoolean('KeepBackup', Other.KeepBackup);
WriteInteger('ThreadCount', UPXThreadCount);
end;
with UserPrefs do begin
WriteBoolean('SaveAsDefault', Other.SaveAsDef);
IniSection := 'Preferences';
end;
end;
--- End code ---
Btw, I'm using TIniPropStorage instead of TXMLPropStorage because I expect the configuration to be easily modified by hand, but the usage is similar.
pyros:
Thanks for the handy reply Leledumb. Using an .ini file seems a nice way to do it.
I was hoping to find a method that didn't require individually reading and writing
each item manually, as well as not minding if the file and record did not match.
I have attempted and failed this in two ways now.
The first was to create a class of TComponent with each 'record field' as a published
property, then create an instance in the TForm1 definition and see if I could add it to
the SessionProperties. That doesn't work.
Next I tried creating my own TComponent containing the values I wanted to save,
as before. Then I write and read it to/from a stream. So far so good. However when
the TComponant changes, the program gets upset. No worries I think, I'll just put
in my own error handler to stop it getting upset. Alas, it still fails to read any fields
into the TComponent type class from the mismatching file.
I think I'll give up on that now and do it your way. Yes, each item must be manually
written and read, but I've run out of options and enthusiasm to automate this and
I certainly don't want to rewrite the TReader class.
Just for the record, here's the working but non-effective code:
--- Code: ---
type
TSettings1 = class(TComponent)
private
fText: String;
fNumber: Integer;
published
property Number: Integer read fNumber write fNumber;
property Text: String read fText write fText;
end;
type
TSettings2 = class(TComponent)
private
fCount: Integer;
fNumber: Integer;
published
property Number: Integer read fNumber write fNumber;
property Count: Integer read fCount write fCount;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Settings1: TSettings1;
Stream: TFileStream;
begin
Settings1 := TSettings1.Create(Self);
Settings1.Text := 'the jungle book';
Settings1.Number := 321;
Stream:=TFileStream.Create('c:\teststream.str', fmCreate);;
Stream.WriteComponent(Settings1);
Stream.Free;
Settings1.Free;
end;
procedure TForm1.HandleReadErrors(Reader: TReader; const Message: string; var Handled: Boolean);
begin
try
Handled:=true;
except
on E:Exception Do Showmessage('strm= '+E.message);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Settings2: TSettings2;
Stream: TFileStream;
Reader: TReader;
begin
Settings2 := TSettings2.Create(Self);
Settings2.Count := 99;
Settings2.Number := -5;
Stream := TFileStream.Create('c:\teststream.str', fmOpenRead);
Reader := TReader.Create(Stream, 4096);
Reader.OnError := @HandleReadErrors;
try
Reader.ReadComponent(Settings2);
except
on E:Exception Do Showmessage('strm= '+E.message);
end;
Stream.Free;
ShowMessage(IntToStr(Settings2.Count) + ' - ' + IntToStr(Settings2.Number));
Settings2.Free;
end;
--- End code ---
Bart:
Why not use a plain old TIniFile for it?
There is an xml tutorial on the wiki if you want xml.
Bart
pyros:
Bart,
there is no reason to not use a plain old TIniFile; the format is irrelevant to the problem.
However, I do not know of a function that will write any record or class to a TIniFile
(or any other type of file) and then read it back into a changed version of that record
or class (when it is changed in later versions of the application).
Navigation
[0] Message Index
[#] Next page