Solved

WriteComponent & ReadComponent with dynamic object arrays...

Posted on 2004-08-16
3
615 Views
Last Modified: 2011-09-20
hello all,
Im hoping someone can help me.
Im saving some objects in my app to a file when it exits, and then reading them back when my app restarts.
Some of the objects are static and some objects are dynamic though.

The code Im listing first works perfectly. It was a test project I made to see if this will work
------------------------------------------------------------------------
var
  F: TFileStream;
  CurDir : String;
  lblTMP : array[0..2] of THTMLabel;

procedure TForm1.btnWriteClick(Sender: TObject);
{ WRITE THE OBJECT TO A FILE VIA STREAM }
var
  i: integer;
begin
  CurDir := ExtractFileDir(Application.ExeName);
  F := TFileStream.Create(CurDir + '\label.dat', fmCreate or fmShareCompat);
  try
    { create a few objects }
    for i := 0 to 2 do
      lblTMP[i] := THTMLabel.Create(nil);
    { add the text to one of the objects }
    with lblTMP[1] do begin
        HTMLText.add("some test to show');
        visible := false;
    end;
    { write the objects (save) }
    for i := 0 to 2 do
      F.WriteComponent(lblTMP[i]);

  finally
    for i := 0 to 2 do
      lblTMP[i].Free;
    F.Free;
  end;
end;

procedure TForm1.btnReadClick(Sender: TObject);
{ READ THE OBJECT FROM A FILE VIA STREAM }
var
  i: integer;
begin
  CurDir := ExtractFileDir(Application.ExeName);
  if FileExists(CurDir + '\label.dat') then begin
    F := TFileStream.Create(CurDir + '\label.dat', fmOpenRead or fmShareDenyWrite);
    try
      for i := 0 to 2 do
        lblTMP[i] := THTMLabel.Create(nil);
      for i := 0 to 2 do
        F.ReadComponent(lblTMP[i]);
      edit2.Text := lblTMP[1].Text;
    finally
      for i := 0 to 2 do
        lblTMP[i].Free;
      F.Free;
    end;
  end;

end;

-------------------------------------------------------------------------
The above code works, but the following does not even though its basically the same
-------------------------------------------------------------------------
type
  TOpenWeekRec = record   { OPEN THIS WEEK }
    trCount    : longint;
    Title      : string[255];
    Link       : string[255];
    RawTitle   : string;
    RawPlayers : string;
    RawPlot    : string;
    RawBuzz    : string;
  end;

  public
    { Public declarations }
    arrOpenWeek : Array of TOpenWeekRec;

var
  arrTMP2 : array of array[0..6] of THTMLabel;
  F: TFileStream;
  CurDir: String;

procedure WriteObjects();
var
  i, x: integer;
begin
  CurDir := ExtractFileDir(Application.ExeName);
  F := TFileStream.Create(CurDir + '\results.dat', fmCreate or fmShareCompat);
  try
    F.WriteComponent(HTMLTreeview1);
    F.WriteComponent(HTMLTreeview2);
    F.WriteComponent(HTMLabel1);
    F.WriteComponent(HTMLabel2);
    { SAVE THE ARRAY COUNT FOR WHEN WE READ IT BACK IN }
    F.Write((arrOpenWeek[0].trCount), sizeof(arrOpenWeek[0].trCount));
    { SAVE DYNAMIC ARRAY NOW }
    SetLength(arrTMP2,arrOpenWeek[0].trCount);
    try
      { CREATE TEMP OBJECTS TO PUT STRINGS INTO }
      x:= 0;
      for i := 0 to high(arrOpenWeek) do
        for x := 0 to 6 do
          arrTmp2[i,x] := THTMLabel.Create(nil);
      { INSERT TEXT INTO THE OBJECTS }
      x:=0;
      for i := 0 to high(arrOpenWeek) do begin
        for x := 0 to 6 do begin
          case x of
            0: arrTmp2[i,x].HTMLText.add(IntToStr(arrOpenWeek[i].trCount));
            1: arrTmp2[i,x].HTMLText.add(arrOpenWeek[i].Title);
            2: arrTmp2[i,x].HTMLText.add(arrOpenWeek[i].Link);
            3: arrTmp2[i,x].HTMLText.add(arrOpenWeek[i].RawTitle);
            4: arrTmp2[i,x].HTMLText.add(arrOpenWeek[i].RawPlayers);
            5: arrTmp2[i,x].HTMLText.add(arrOpenWeek[i].RawPlot);
            6: arrTmp2[i,x].HTMLText.add(arrOpenWeek[i].RawBuzz);
          end;
        end;
      end;
      { WRITE THE OBJECTS INTO THE STREAM }
      for i := 0 to high(arrTmp2) do
        for x := 0 to 6 do
          F.WriteComponent(arrTmp2[i,x])
    finally
      { DELETE TEMP OBJECTS }
      for i := 0 to high(arrTmp2) do
        for x := 0 to 6 do
          arrTmp2[i,x].free;
    end;
  finally
    F.Free;
  end;
end;

procedure ReadObjects();
var
  count, i, x: integer;
begin
  CurDir := ExtractFileDir(Application.ExeName);
  if FileExists(CurDir + '\results.dat') then begin
    F := TFileStream.Create(CurDir + '\results.dat', fmOpenRead or fmShareDenyWrite);
    try
      F.ReadComponent(HTMLTreeview1);
      F.ReadComponent(HTMLTreeview2);
      F.ReadComponent(HTMLabel1);
      F.ReadComponent(HTMLabel2);
      F.Read(count,1) ;
      { LOAD DYNAMIC ARRAY NOW }
      SetLength(arrTmp2, count);
      try
        { CREATE TEMP OBJECTS TO STORE THE STRINGS }
        for i := 0 to high(arrOpenWeek) do
          for x := 0 to 6 do
            arrTmp2[i,x] := THTMLabel.Create(nil);
        { READ THE OBJECT INTO THE TEMP OBJECT }
        for i := 0 to high(arrTmp2) do
          for x := 0 to 6 do
            F.ReadComponent(arrTmp2[i,x])  { <- ERROR OCCURS HERE!!}
      finally
      { DELETE TEMP OBJECTS }
        for i := 0 to high(arrTmp2) do
          for x := 0 to 6 do
            arrTmp2[i,x].free;
      end;
    finally
      f.Free;
    end;
  end;
end;

--------------------------------------------------
There are no problems saving the objects, just reading them.
The error always shows up when I -> F.ReadComponent(arrTmp2[i,x])
EReadError "Invalid stream format"

Like I said, the 1st prj code works, but not the 2nd.
And the only real difference between them is the use of a multi-dimensional array and a record.

thanx for any help
0
Comment
Question by:LMuadDIb
  • 2
3 Comments
 
LVL 33

Accepted Solution

by:
Slick812 earned 200 total points
Comment Utility
hello  LMuadDIb, I do not have time right now to get your code and run it, to see what is problem, , but from looking at it, I can see something that I know would not work for me in code that I have written for file stream reads, , , your line -

F.Read(count,1) ;

is NOT CORRECT

should it be

F.Read(count,4) ; // count is integer, which is 32 bits (4 bytes)

or more better

F.Read(count, SizeOf(count)) ;

you might add a line to test the value

F.Read(count, SizeOf(count)) ;
if count <> 6 then ShowMessage('Not Six');
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
also, here is the addy for a web page which has some info about reading and writting to a TFileStream for delphi

http://www.angelfire.com/hi5/delphizeus/customfiles.html
0
 
LVL 4

Author Comment

by:LMuadDIb
Comment Utility
thanx  for the help Slick812 :)
and nice link too
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now