2

Why does this code not work?

I am writing an application that has ability to save and load its own files and need to know how to stream objects to a file using FileStream.

procedure TForm1.btnSaveClick(Sender: TObject);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create('c:\temp\a.my', fmCreate);
  try
    fs.WriteBuffer(Image1.Picture.Graphic, SizeOf(TGraphic));
  finally
    fs.Free;
  end;

  ShowMessage('ok');

  Image1.Picture.Graphic := nil;
end;

procedure TForm1.btnLoadClick(Sender: TObject);
var
  fs: TFileStream;
  g:  TGraphic;
begin
  fs := TFileStream.Create('c:\temp\a.my', fmOpenRead);
  try
    fs.ReadBuffer(g, SizeOf(TGraphic));

    Image1.Picture.Graphic := g;
  finally
    fs.Free;
  end;

  ShowMessage('ok');

end;

EDIT 1: Found the way to do it, but need some more help:

procedure TForm1.btnSaveClick(Sender: TObject);
var
  fs: TFileStream;
  s:  TMemoryStream;
  buf: TBytes;
begin
  fs := TFileStream.Create('c:\temp\a.my', fmCreate);
  s  := TMemoryStream.Create;
  try
    Image1.Picture.Graphic.SaveToStream(s);

    SetLength(buf, s.Size);
    s.Position := 0;
    s.ReadBuffer(buf[0], s.Size);

    //fs.WriteBuffer(, SizeOf(Integer));  <-here how do I save an integer which represents the size of the buffer? (so that when reading back i read this first.) 

    fs.WriteBuffer(buf[0], s.Size);
  finally
    s.Free;
    fs.Free;
  end;

  ShowMessage('ok');

  Image1.Picture.Graphic := nil;
end;
  • This is related to your other question that I answered with a full code snippet: http://stackoverflow.com/questions/7190998/after-assigning-nil-to-timage-picture-graphic-to-clear-the-picture-how-can-i-use/ – Remy Lebeau Aug 25 '11 at 20:00

1 Answers1

4

What you have done there is stream the reference, i.e. a pointer. What you need to stream is the contents. You can that with SaveToFile and LoadFromFile.

Regarding your update, assign s.Size to a local variable of type Integer and then use WriteBuffer to save it. In reverse, use ReadBuffer to read into a local variable.

If I were you I would write direct to the file and avoid the memory streak. Use the Position property of TStream to seek around the file. So write 0 for then length, write the graphic, seek back to the beginning and write the true length accounting for the 4 bytes of the length.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks for responding. I have other objects in addition to the TGraphic so I have to use TFileStream's WriteBuffer and ReadBuffer to save and load files. I am going to edit my post to show my current code, in which i have a related question. –  Aug 25 '11 at 10:03
  • 1
    It's generally best to ask one question at a time. I already answered this one. – David Heffernan Aug 25 '11 at 10:05
  • Need to know how to: "how do I save an integer which represents the size of the buffer?" in EDIT 1 –  Aug 25 '11 at 10:07
  • @Steve See this [post](http://stackoverflow.com/questions/7105995/delphi-store-data-in-somekind-of-structure/7107018#7107018), it should give you an idea how to save / load data to/from stream. – ain Aug 25 '11 at 11:29
  • @ain: Thanks. I see that you can just write an Integer using WriteBuffer. I was previously confused thinking that buffer has to be a memory (bytes) or string type. –  Aug 25 '11 at 13:16