Nie chce mi się zapoznawać z zawiłościami Twojego kodu @Patryk Winner, dlatego pokażę Ci przykładowy kod odpowiedzialny za zapis całej macierzy do pliku oraz jej odczyt. Nie wiem którego Delphi używasz, ja nie używam żadnego, dlatego podam przykład napisany we Free Pascalu.
Przyjmijmy, że struktury danych wyglądają tak (takie same jak Twoje, ale sformatowane):
Kopiuj
type
TItem = record
Empty: Byte;
Caption: String;
Subitems: TStringList;
end;
type
TItems = array of TItem;
Prosta struktura zawierająca pola z jednym bajtem, ciągiem znaków i listą, a także zwykła dynamiczna macierz takich rekordów. Aby zapisać do pliku całą macierz, należy najpierw zapisać liczbę rekordów, a potem każdy z nich i dla każdego z nich, każde pole z osobna:
Kopiuj
procedure SaveItemsToFile(const AFileName: String; const AItems: TItems);
var
Output: TFileStream;
ItemIndex, SubitemIndex: Integer;
begin
Output := TFileStream.Create(AFileName, fmCreate or fmShareDenyWrite);
try
Output.WriteDWord(Length(AItems));
for ItemIndex := Low(AItems) to High(AItems) do
with AItems[ItemIndex] do
begin
Output.WriteByte(Empty);
Output.WriteAnsiString(Caption);
Output.WriteDWord(Subitems.Count);
for SubitemIndex := 0 to Subitems.Count - 1 do
Output.WriteAnsiString(Subitems[SubitemIndex]);
end;
finally
Output.Free();
end;
end;
Jak pisałem wcześniej — najpierw zapisuje się liczbę rekordów, następnie rekordy. Dla każdego rekordu najpierw bajtowa flaga pustości, potem ciąg znaków (ja mam do dyspozycji metodę WriteAnsiString
, która zapisuje najpierw długość ciągu, a następnie jego wartość), następnie liczbę subitemów i każdy subitem z osobna (też jako para długość-wartość).
Odczyt wygląda podobnie, ale z tą różnicą, że trzeba nadać rozmiar macierzy (raz!), no i w każdym odczytywanym rekordzie należy stworzyć instancję TStringList
. Reszta pozostaje bez zmian.
Kopiuj
procedure LoadItemsFromFile(const AFileName: String; out AItems: TItems);
var
Input: TFileStream;
ItemsCount, SubitemsCount: Integer;
ItemIndex, SubitemIndex: Integer;
begin
Input := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
try
try
ItemsCount := Input.ReadDWord();
SetLength(AItems, ItemsCount);
for ItemIndex := 0 to ItemsCount - 1 do
AItems[ItemIndex].Subitems := TStringList.Create();
for ItemIndex := 0 to ItemsCount - 1 do
with AItems[ItemIndex] do
begin
Empty := Input.ReadByte();
Caption := Input.ReadAnsiString();
SubitemsCount := Input.ReadDWord();
for SubitemIndex := 0 to SubitemsCount - 1 do
Subitems.Add(Input.ReadAnsiString());
end;
except
for ItemIndex := 0 to ItemsCount - 1 do
AItems[ItemIndex].Subitems.Free();
SetLength(AItems, 0);
raise;
end;
finally
Input.Free();
end;
end;
W razie gdyby wystąpił błąd podczas odczytywania, referencje Subitems
zostaną zwolnione, rozmiar macierzy ustawiony na 0
, a wyjątek wydostanie się z procedury, aby można było na zewnątrz niej zareagować na błędy odczytu.
Działania kodu nie sprawdzałem — tylko to czy się kompiluje, więc miej to na uwadze.