[Delphi] Zapis rekordu z nieograniczoną wielkością String

0

Witam. Piszę swoją małą obsługę zapisu i odczytu rekordów z pliku. Z góry proszę o nie polecanie mi gotowych baz typu SQLight itp ;) . Chce mieć coś małego i szybkiego dla własnych drobnych potrzeb. I tak, procedury prawdopodobnie działają tylko niektóre osoby zgłaszają mi błąd odczytu bazy. Ja nigdy takiej sytuacji nie miałem, ale to chyba dlatego że nie używałem własnego kreatora starej bazy na nową ;) Jestem przekonany że coś skopałem w kreatorze ale chciałbym aby jakiś spec obejrzał procedurki odczytu i zapisu (zwłaszcza to czy można wczytywać niepełną wielkość rekordu - wyjaśnione w kodzie). Mam standardowy rekord który ma w sobie pola o stałej długości jak i jedno o nieograniczonej. Rozwiązałem to tak że mam jedno pole pomocnicze które pamięta ilość znaków pola o nieograniczonej wielkości. Wskaźniki do rekordów trzymam w TList.
Kod:

type
  TBaza = packed record
    Imie: String[25];
    Nazwisko: string[25];
    Wiek: Byte;
    DlugoscNotki: Integer;
    Notka: String;
end;

//zapis
procedure ZapisBazy;
 var
  S: TFileStream;
  i, PakietSize: Integer;
  tmpRec: PBaza;
  tmNotka: String;
begin
  S := TFileStream.Create(PathBaza, fmCreate);

  try
    try
      //faktyczna wielkosc rekordu do zapisu (bez wielkosci zmiennej String)
      PakietSize := SizeOf(TBaza)-SizeOf(String);
      //petla po rekordach i zapis do pliku
      for i:=0 to Pred(ListaTList.Count) do
      begin
        tmpRec := ListaTList.Items[i];
        //zapamietuje wielkosc notki aby przy odczycie wiedziec ile bajtow pobrac
        tmpRec^.DlugoscNotki := Length(tmpRec^.Notka);
        //rekord
        S.WriteBuffer(tmpRec^, PakietSize);
        //notka
        tmNotka := tmpRec^.Notka;
        S.Write(tmNotka[1], tmpRec^.DlugoscNotki);
      end;
    except
      InfoMsg('Błąd podczas zapisu bazy danych', NAZWAFULL, MB_OK or MB_ICONERROR);
    end;
  finally
    S.Free;
  end;
end;

//odczyt
procedure OdczytBazy;
 var
  S: TFileStream;
  tmpRec: PBaza;
  PakietSize: Integer;
  tmpNotka: String;
begin
  //jak nie ma pliku bazy to wychodze
  if not FileExists(PathBaza) then Exit;
  S := TFileStream.Create(PathBaza, fmOpenReadWrite or fmShareDenyWrite);
  try
    //faktyczna wielkosc rekordu do odczytu (bez wielkosci zmiennej String)
    PakietSize := SizeOf(TBaza)-SizeOf(String);
    //petla w pliku i odczyt rekordow
    try
      while S.Position<S.Size do
      begin
          New(tmpRec);
          //odczyt rekordu
          S.ReadBuffer(tmpRec^, PakietSize);
          //odczyt ostatniej notki
          SetLength(tmpNotka, tmpRec^.DlugoscNotki);
          S.ReadBuffer(tmpNotka[1], tmpRec^.DlugoscNotki);
          tmpRec^.Notka := tmpNotka;
          SetLength(tmpNotka, 0);
          //dodaje do listy
          ListaTList.Add(tmpRec);
      end;
      //sortuje liste
      ListaTList.Sort(@Posortuj);
    except
      InfoMsg('Błąd podczas odczytu bazy danych', NAZWAFULL, MB_OK or MB_ICONERROR);
    end;
  finally
    S.Free;
  end;
end;
0

Kod wyglada poprawnie (wg. mnie oczywiscie). Sprobuj moze ustawiac rozmiar i wartosc bezposrednio do rekordu

SetLength(tmpRec.c, tmpRec.DlugoscNotki)
ReadBuffer(tmpRec.c[1], tmpRec.DlugoscNotki)

albo zamiast Notka typu string zmien na pChar i zrob wtedy tak:

zamist
tmpRec^.Notka := tmpNotka;

zmien na
tmpRec.Notka := @tmpNotka;

ale jak napislem twoj kod wyglada okej :|.

0

Dzięki. Czyli nic nie szkodzi że wczytuje okrojoną wielkość rekordu (minus SizeOf(String))? Warunkiem poprawnego działania to oczywiście to, że Pole z nieograniczoną wielkością zawsze musi być ostatnie w deklaracji typu?

0

Tak wg mnie takie odejmowanie jest jak najbardziej na miejscu. Ogulnie string zajmuje 4bajty i przechowuje adres w pamieci gdzie znajduje sie twoj tekst. Takze gdy "Notka" zawiera tekst o dlugosci 20 wtedy twoj record nie zmieni rozmiaru.

Mowiles ze ty sam niemasz tego problemu wiec niezabardzo masz jak sprawdzic.

1 użytkowników online, w tym zalogowanych: 0, gości: 1