2

Can I, or do I have to declare it as a class with it's own SaveToStream method?

It is only data, no functions (although I might now add getters & setters)

Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551
  • 2
    possible duplicate of [Writing complex records to file](http://stackoverflow.com/questions/4533376/writing-complex-records-to-file) – Arnaud Bouchez Nov 08 '11 at 07:18

2 Answers2

9

https://github.com/KrystianBigaj/kblib - you could try this (no need to limit strings to constant size, and works with complex records, load/save with one line).

Similar questions:

Krystian Bigaj
  • 1,295
  • 8
  • 14
  • 3
    +1 because you identified the duplicated question. And perhaps worth adding to the list [this OpenSource unit](http://blog.synopse.info/post/2011/03/12/TDynArray-and-Record-compare/load/save-using-fast-RTTI) - working for Delphi 5 up to XE2. – Arnaud Bouchez Nov 08 '11 at 07:19
  • @Arnaud Bouchez - thanks, I've added link to main page of kblib :) – Krystian Bigaj Nov 08 '11 at 13:05
5

suppose you have the following record

type
  TMyRecord = record
    FirstName: string[100]; // 100 characters max. for First name
    LastName: string[100]; // 100 characters max. for Last name
    Age: Byte;
    DateOfBirth: TDateTime;
  end;
const
  // if you are using Delphi 2009 and above, 
  // then either change *string[100]* to *AnsiString[100]* or use a different
  // approach to save the string, read bellow
  szMyRecord = SizeOf( TMyRecord ); // storing it will make your code run faster if you write a lot of records

Now, in order to write the above structure to a stream, you need to:

procedure WriteRecord(
  const ARecord: TMyRecord;
  const AStream: TStream // can be a TMemoryStream, TFileStream, etc.
);
begin
  AStream.Write(ARecord, szMyRecord);
end;

it is important to note that declaring FirstName as "string" will not save the characters in FirstName, you need to declare FirstName as I did "string[100]" or use a special method to write a string field, for example:

type
  TMyRecordWithVeryLongStrings = record
    LenFirstName: Integer; // we store only the length of the string in this field
    LenLastName: Integer; // same as above
    Age: Byte;
    DateOfBirth: TDateTime;
    FirstName: string; // we will ignore this field when writing, using it for value
    LastName: string; // same as above
  end;

const
  // we are ignoring the last two fields, since the data stored there is only a pointer,
  // then we can safely assume that ( SizeOf( string ) * 2 ) is the offset
  szMyRecordWithVeryLongStrings = SizeOf( TMyRecordWithVeryLongStrings ) - ( SizeOf( string ) * 2 );

// the difference between this method and above is that we first write the record
// and then the strings
procedure WriteRecord(
  ARecord: TMyRecordWithVeryLongStrings;
  AStream: TStream // can be a TMemoryStream, TFileStream, etc.
);
const szChar = sizeof(char);
begin
  // ensure the length of first and Last name are stored in "Len + Name" field
  ARecord.LenFirstName := Length( ARecord.FirstName );
  ARecoord.LenLastName := Length( ARecord.Lastname );
  // write the record
  AStream.Write(ARecord, szMyRecordWithVeryLongStrings);
  // write First name value
  AStream.Write(
    Pointer( ARecord.FirstName )^, // value of first name
    szChar * ARecord.LenFirstName
  );
  // repeat as above for last name
  AStream.Write(
    Pointer( ARecord.LastName )^, // value of first name
    szChar * ARecord.LenLastName
  );
end;

Now, in order to read the "long strings", you first read the record:

procedure ReadRecord(
  ARecord: TMyRecordWithVeryLongStrings;
  AStream: TStream
);
begin
  AStream.Read(Arecord, szMyRecordWithVeryLongStrings );
  // now read first and last name values which are right after the record in the stream
  AStream.Read(Pointer(ARecord.FirstName)^, szChar * ARecord.LenFirstName );
  AStream.Read(Pointer(ARecord.,LastrName)^, szChar * ARecord.LenLastName );
end;

I hope it helps (:

  • +1 and thanks for such a comprehensive example!! I will copy/paste and test it and award you the answer when I get it working. Thanks !! – Mawg says reinstate Monica Nov 08 '11 at 06:21
  • 3
    Please note that this only works with short strings (string[xx]). They are Ansi only. All other strings are pointers and you need some more work to write them. – Toon Krijthe Nov 08 '11 at 06:55
  • ShortStrings are really deprecated since Delphi 2009. This is IMHO not a good option for records saving, and will be an awful waste of space. – Arnaud Bouchez Nov 08 '11 at 07:19
  • @ArnaudBouchez you are right, however I don't see what Delphi version he is using, maybe short strings is the way to go(he seems a C++ guy). –  Nov 08 '11 at 07:28