1
votes

I am saving some custom created Objects classes (Stream data) to File.

I need to be able to load the contents of the File into a TStringList so I can append a new line to the end of the File, and then Save the changes.

This is not working though because LoadFromFile cannot seem to parse the File correctly. I assume because of the funny characters the Stream Saves to File as, and TStringList expects plain textual information.

How can I do the following:

  • Read any Raw Binary File into a TStringList.
  • Add my new Line, eg StringList1.Add(MyString);
  • Save the Raw Binary File again.

This question actually relates to another question I asked: Save a CRC value in a file, without altering the actual CRC Checksum?

This is what I am trying to do:

  • Calculate the CRC Checksum of my Saved Stream File.
  • Add the CRC Value to the end of the File.
  • Re-save the File.

Then when I attempt to Open my Stream File:

  • Assign the CRC Value (at the end of the File) to a variable.
  • Delete the CRC Value from the File.
  • Save the Stream File as a new Temp File.
  • Calculate and Compare the CRC of the Temp File, with the CRC stored in the variable.
  • If the CRC of the File matches the internal stored CRC Value, I can process the File as normal.

But I don't know how to Read or Write the Raw Binary Data of the File.

I would be grateful if someone could give me some help and advice thanks :)

1
You are saving a checksum into a text file? Is that correct? I still don't understand why you need the checksum.David Heffernan
Saving to the Stream File, I am doing this so that whenever a File is opened from my Application I can determine if in fact the File was originally saved from my program.user741875
What version of Delphi are you using? It matters in particular for Unicode strings (or not)David Heffernan
It would be much better to detect a corrupt file and report an error. If the user messes the file up then that's their problem. Store it under their user profile and there's no reason for them to mess around with it.David Heffernan
Craig; A free tip; Binary files are trouble. If you don't need to make custom binary file formats, then don't. Text files are much more "rugged and reliable", and easier to troubleshoot when malformed.Warren P

1 Answers

6
votes

This class descends from TStringList and adds a check value at the end when writing to a file. This value is checked whenever the file is read.

type
  TCRCStringList = class(TStringList)
  type
    TCRC = LongWord;
  private
    function CalcCRC(Stream: TStream): TCRC;
  public
    procedure LoadFromStream(Stream: TStream; Encoding: TEncoding); override;
    procedure SaveToStream(Stream: TStream; Encoding: TEncoding); override;
  end;

function TCRCStringList.CalcCRC(Stream: TStream): TCRC;
begin
  Result := 42;  // place CRC calculation here
end;

procedure TCRCStringList.LoadFromStream(Stream: TStream; Encoding: TEncoding);
var
  crc: TCRC;
  temp: TMemoryStream;
begin
  temp := TMemoryStream.Create;
  try
    temp.CopyFrom(Stream, Stream.Size - Sizeof(crc));
    Stream.Read(crc, Sizeof(crc));
    if crc <> CalcCRC(temp) then
      raise Exception.Create('CRC error');
    temp.Position := 0;
    inherited LoadFromStream(temp, Encoding);
  finally
    temp.Free;
  end;
end;

procedure TCRCStringList.SaveToStream(Stream: TStream; Encoding: TEncoding);
var
  crc: TCRC;
  temp: TMemoryStream;
begin
  temp := TMemoryStream.Create;
  try
    inherited SaveToStream(temp, Encoding);
    temp.Position := 0;
    crc := CalcCRC(temp);
    temp.Position := temp.Size;
    temp.Write(crc, Sizeof(crc));
    Stream.CopyFrom(temp, 0); // count = 0 copies the whole stream from the beginning
  finally
    temp.Free;
  end;
end;