Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Problem saving with TfileStream

Status
Not open for further replies.

scoopbh

Programmer
Feb 28, 2003
6
BR
Hi, I need a method to save a object (with structure and data) to a file, then recover the data to store it in object of the same type. (in the example I save object tim[1] and then load it from file to tim[2] they are teamme type).

I tried the procedure below, it works fine, but (it's hard to understand) when I add a new component in the main form it stop to work (i try to repeat the load procedure and now it get access violation). Anyone can help-me?

type
teamme = class(TPersistent)
public
name: string;
tjog: array[1..25] of jog;
end;

var
Form1: TForm1;
tim: array[1..100] of teamme;


procedure saveobj;
var
f: TFileStream;
begin
f:= TFileStream.Create('test.sav', fmCreate);
try
f.Writebuffer(tim[1],sizeof(tim[1]));
finally
f.Free;
end;
end;

procedure getobj;
var
o: TFileStream;
begin
o := TFileStream.Create('test.sav', fmOpenRead);
try
o.Readbuffer(tim[2],sizeof(tim[2])) ;
finally
o.Free;
end;

end;
 
Access violation usually indicates you neglected to create your object before trying to use it.

The following does what I think you are trying to do. (You didn't indicate what "jog" was, so I used integer.)
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  jog = integer;

type
  teamme = class(TPersistent)
    public
      name: string;
      tjog: array[1..25] of jog;
    end;

type
  TForm1 = class(TForm)
    pbSaveObject: TButton;
    pbGetObject: TButton;
    Edit1: TEdit;
    procedure pbSaveObjectClick(Sender: TObject);
    procedure pbGetObjectClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  CRLF = #13 + #10;
var
  Form1: TForm1;
  tim: array[1..100] of teamme;


implementation

{$R *.DFM}

procedure saveobj;
var
  f: TFileStream;
begin
  f:= TFileStream.Create('test.sav', fmCreate);
  try
    f.Writebuffer(tim[1],sizeof(tim[1]));
  finally
    f.Free;
  end;
end;

procedure getobj;
var
  o: TFileStream;
begin
  o := TFileStream.Create('test.sav', fmOpenRead);
  try
    o.Readbuffer(tim[2],sizeof(tim[2])) ;
  finally
    o.Free;
  end;  
end;

procedure TForm1.pbSaveObjectClick(Sender: TObject);
begin
  saveobj;
end;

procedure TForm1.pbGetObjectClick(Sender: TObject);
begin
  getobj;
  ShowMessage( tim[2].Name + CRLF
              + '  1 = ' + IntToStr(tim[2].tjog[1]) + CRLF
              + '  2 = ' + IntToStr(tim[2].tjog[2]) );
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i := Low(tim) to High(tim) do
    tim[i] := teamme.Create;
  tim[1].name := 'TIM-ONE';
  tim[1].tjog[1] := 42;
  tim[1].tjog[2] := 43;
end;

end.
 
Playing with this a little more, the savobj/getobj routines are writing and reading the memory address of the object, not the objects themselves (i.e., not the data). You can see for yourself with a binary viewer on test.sav -- or just check the properties. (It's only four bytes long.)

I'm going to have to spend a little more time on this. Good opportunity to brush up on file streams.
 
I couldn't find a straightforward way to do what you want. Here is one way to do it, but it's a little complex...

Again I am assuming that "jog" is an integer. If it is not, then this will need further refinement.

To save an instance of "tim"
Code:
procedure savetim( Index:integer );
var
  f: TFileStream;
  i,ilength: integer;
begin
  f:= TFileStream.Create('test.sav', fmCreate);
  try
    ilength := Length( tim[Index].Name ) + 1;
    f.Write( ilength, SizeOf(Integer));
    f.Write(PChar(tim[Index].Name)^, ilength);
    for i := Low(tim[Index].tjog) to High(tim[Index].tjog) do
      f.Write(tim[Index].tjog[i],Sizeof(Integer));
  finally
    f.Free;
  end;
end;
To load/refresh an instance of "tim"
Code:
procedure gettim( Index:integer );
var
  o: TFileStream;
  i,ilength: integer;
  b: array[0..255] of char;
begin
  o := TFileStream.Create('test.sav', fmOpenRead);
  try
    o.Read( ilength, SizeOf(Integer));
    o.Read( b, ilength);
    tim[Index].Name := b;
    for i := Low(tim[Index].tjog) to High(tim[Index].tjog) do
      o.Read(tim[Index].tjog[i],Sizeof(Integer));
  finally
    o.Free;
  end;
end;
To demonstrate/test the routines:
Code:
procedure TForm2.pbSaveObjectClick(Sender: TObject);
begin
  savetim( 1 );
end;

procedure TForm2.pbGetObjectClick(Sender: TObject);
begin
  gettim( 2 );
  ShowMessage( tim[2].Name + CRLF
              + '  1 = ' + IntToStr(tim[2].tjog[1]) + CRLF
              + '  2 = ' + IntToStr(tim[2].tjog[2]) );
end;
to initialize the objects/array:
Code:
procedure TForm2.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i := Low(tim) to High(tim) do
    tim[i] := teamme.Create;
  tim[1].name := 'TIM-ONE';
  tim[1].tjog[1] := 42;
  tim[1].tjog[2] := 43;
end;
Hope this helps. Let me know if you find a simpler way.
 
Ok. I think you'll like this. Instead of using TPersistent, use TComponent and set it up just like you were going to add a component to your IDE, only you don't go that far. Just declare it and use it. (It gets registered temporarily when the program runs.) Then instead of trying to write your own TFileStream, let Delphi do it for you behind the scene. Use WriteComponentResFile and ReadComponentResFile instead.

Here is a complete unit. All you need to do to test it is drop two buttons on a new form, name them appropriately then paste this code over everything.

The only downside is Delphi (at least Delphi 4 which is what I have here) doesn't allow an array as a published property, but that is only a minor annoyance.
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs, StdCtrls;

type
  jog = integer;

  Tteamme = class(TComponent)
    private   
      { Private declarations }
    public           
      { Public declarations }
      Fname: string;
      Fjog: array[1..25] of jog;
      function Getjog(Index:integer):jog;
      procedure Setjog(Index:integer;Value:jog);
    published     
      { Published declarations }
      property  name:string  read Fname write Fname;
      property  tjog1:jog index 1 read Getjog write Setjog; 
      property  tjog2:jog index 2 read Getjog write Setjog;
      property  tjog3:jog index 3 read Getjog write Setjog;
      property  tjog4:jog index 4 read Getjog write Setjog;
      property  tjog5:jog index 5 read Getjog write Setjog;
      property  tjog6:jog index 6 read Getjog write Setjog;
      property  tjog7:jog index 7 read Getjog write Setjog;
      property  tjog8:jog index 8 read Getjog write Setjog;
      property  tjog9:jog index 9 read Getjog write Setjog;
      property  tjog10:jog index 10 read Getjog write Setjog;
      property  tjog11:jog index 11 read Getjog write Setjog;
      property  tjog12:jog index 12 read Getjog write Setjog;
      property  tjog13:jog index 13 read Getjog write Setjog;
      property  tjog14:jog index 14 read Getjog write Setjog;
      property  tjog15:jog index 15 read Getjog write Setjog;
      property  tjog16:jog index 16 read Getjog write Setjog;
      property  tjog17:jog index 17 read Getjog write Setjog;
      property  tjog18:jog index 18 read Getjog write Setjog;
      property  tjog19:jog index 19 read Getjog write Setjog;
      property  tjog20:jog index 20 read Getjog write Setjog;
      property  tjog21:jog index 21 read Getjog write Setjog;
      property  tjog22:jog index 22 read Getjog write Setjog;
      property  tjog23:jog index 23 read Getjog write Setjog;
      property  tjog24:jog index 24 read Getjog write Setjog;
      property  tjog25:jog index 25 read Getjog write Setjog;
   end;

  TForm1 = class(TForm)
    pbWriteComponent: TButton;
    pbReadComponent: TButton;
    procedure FormCreate(Sender: TObject);
    procedure pbWriteComponentClick(Sender: TObject);
    procedure pbReadComponentClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  CRLF = #13 + #10;

var
  Form1: TForm1;
  tim: array[1..100] of Tteamme;

implementation

{$R *.DFM}

{ Tteamme }

function Tteamme.Getjog(Index: integer): jog;
begin
  Result := Fjog[Index];
end;

procedure Tteamme.Setjog(Index: integer; Value: jog);
begin
  Fjog[Index] := Value;
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i := Low(tim) to High(tim) do
    tim[i] := Tteamme.Create(self);
  tim[1].name := 'TIM-ONE';
  for i := 1 to 25 do tim[1].Fjog[i] := 41 + i;
end;

procedure TForm1.pbWriteComponentClick(Sender: TObject);
begin
  WriteComponentResFile( 'test2.res', tim[1] );
end;

procedure TForm1.pbReadComponentClick(Sender: TObject);
begin
  ReadComponentResFile( 'test2.res', tim[2] );
  ShowMessage( tim[2].Name + CRLF
              + '  1 = ' + FloatToStr(tim[2].tjog1) + CRLF  
              + '  2 = ' + FloatToStr(tim[2].tjog2) + CRLF
              + '  3 = ' + FloatToStr(tim[2].tjog3) );
end;

initialization
  RegisterClasses([Tteamme]);

end.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top