5

please can someone help me in saving and loading its Dynamic array from a Stream

const
      iGlobHolderCount = 100;

    type
      TFiLeSpec = record
        iSize: Integer;
      end;

      TFileSpecLst = array of TFiLeSpec;

      TFiLeSpecList = record
        iMin: Integer;
        iMax: Integer;
        iCount: Integer;
        FileSpecLst: TFileSpecLst;
      end;


var
FFileSpec: array of TFiLeSpec;

FFileSpecList: array [1 .. iGlobHolderCount] of TFiLeSpecList;
Sergey Kudriavtsev
  • 10,328
  • 4
  • 43
  • 68
Alexis
  • 141
  • 1
  • 5
  • 1
    What did you try? It looks like a `Show me teh codez` question right now. – Cosmin Prund Jan 27 '12 at 11:00
  • Did you try the technique shown in my answer to your other question (http://stackoverflow.com/questions/8819885/delphi-save-and-load-binary-tree) or the variants suggest in the first comment to your other question? (http://stackoverflow.com/questions/3820996/delphi-2010-how-to-save-a-whole-record-to-a-file). You should try to solve this yourself and post the failing code. Without that, it really is a `"Show me teh codez"` question. Voting to close as "too localized" because this would only help YOU, no one else, ever. – Cosmin Prund Jan 27 '12 at 11:05
  • @Cosmin Prund , No it's not Show me teh codez , But just to be honest i don't know how to Save and Load the Dynamic Array from Stream . – Alexis Jan 27 '12 at 11:06
  • Do me a favor. Read the answers for the two questions I linked and try to solve this yourself. If you *try* and fail, post back a comment in no less then 60 minutes and I'll give you the code. Hint: the second question contains code to save a dynamic array. – Cosmin Prund Jan 27 '12 at 11:08
  • http://stackoverflow.com/questions/3820996/delphi-2010-how-to-save-a-whole-record-to-a-file This's not my question , But i will try based on the suggestions . Thank you – Alexis Jan 27 '12 at 11:08
  • Call `Stream.Write` to write and `Stream.Read` to read. Before anyone can reasonably help you, in my view, you need to tell us what format you want. Binary? And if so, do you want to build in the ability to extend the file format at a later date. Or do you want it as text? XML? JSON? YAML? – David Heffernan Jan 27 '12 at 11:09
  • yes as Binary , and i will not extend the file format at a later date. OK i will try and post back my code . – Alexis Jan 27 '12 at 11:13
  • Is `iCount` related to the dimensions of `FileSpecLst`? If so then you don't need that field. – David Heffernan Jan 27 '12 at 11:15
  • No iCount is related to TFiLeSpecList , latter i will use to Count its records . – Alexis Jan 27 '12 at 11:21

2 Answers2

6

Write first the length of an array, and next the array data:

type
  TItem = Integer;
  TItemArray = array of TItem;

var
  Stream: TStream;
  Arr: TItemArray;
  L: LongWord;

begin
  Arr:= TItemArray.Create(1, 2, 3);
// To save
  Stream:= TFileStream.Create('C:\Temp\test.bin', fmCreate);
  L:= Length(Arr);
  Stream.WriteBuffer(L, SizeOf(L));
  Stream.WriteBuffer(Pointer(Arr)^, L * SizeOf(TItem));
  Stream.Free;
// To load
  Stream:= TFileStream.Create('C:\Temp\test.bin', fmOpenRead);
  Stream.ReadBuffer(L, SizeOf(L));
  SetLength(Arr, L);
  Stream.ReadBuffer(Pointer(Arr)^, L * SizeOf(TItem));
  Stream.Free;
end;
kludg
  • 27,213
  • 5
  • 67
  • 118
5

Another solution, working from Delphi 5 up to XE2, is to use some features of one our core OpenSource unit.

In fact, it implements:

  • some low-level RTTI functions for handling record types: RecordEquals, RecordSave, RecordSaveLength, RecordLoad;
  • a dedicated TDynArray object, which is a wrapper around any dynamic array, able to expose TList-like methods around any dynamic array, even containing records, strings, or other dynamic arrays. It's able to serialize any dynamic array.
  • Serialization uses an optimized binary format, and is able to save and load any record or dynamic array as RawByteString.

You can code, e.g.

var
  FFileSpec: array of TFiLeSpec;
  TFileSpecList = array of TFiLeSpecList;
  FFileSpecList: TFileSpecList;

var FSL: TDynArray;
    Bin: RawByteString;
begin
  FSL.Init(TypeInfo(TFiLeSpecList),FFileSpecList);
  // ... then you use FFileSpecList[] as usual
  // ... or use some methods of FSL:
  if FSL.Count>0 then
    FSL.Delete(0);
  FSL.Add(FFileSpec);
  FSL.Clear;
  // then you can serialize the content to binary
  Bin := FSL.SaveTo;
  // use FSL.LoadFrom(Bin) to read the whole array content back
  // or you can use a TStream 
  FSL.SaveToStream(aStream); 
  FSL.Clear;
  aStream.Position := 0;
  FSL.LoadFrom(aStream);
  // you do not need to release nor Free FSL: this is a wrapper around FFileSpecList
end;

Note that I've replace your TFileSpecList by a dynamic array, but you may use a fixed array instead, inside a record to provide additional RTTI - then use RecordLoad / RecordSave functions. It will save the internal dynamic array content using RTTI (even with Delphi 5), handling any string or nested array within.

It's used by our mORMot framework (e.g. for serialization of dynamic arrays into the DB), but it's not part of it: just one unit, nor SQLite3 nor the whole ORM classes are needed.

See this page for additional information.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • Updated documentation at http://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html#TITL_48 With a lot of new features, including JSON serialization. – Arnaud Bouchez Jun 05 '15 at 09:42