TFileStream + packed record

0

Witam. Mam takie jedno pytanie.... czy jesli mam naprzyklad typ:
TMojTyp = packed record
l1:TString[40];
l2:TString[10];
l3:TString[18];
end;
i kilka danych:
mojadana :TMojTyp;
to czy jesli uzyje strumieni do zapisu i odczytu tej danej z pliku:
f.write(mojadana, sizeof(mojadana));
f.read(mojadana, sizeof(mojadana));
to czy beda bledy tego typu ze po odczytaniu
l1 bedzie zawieralo czesc l2 a l2 bedzie uciete z poczatku itd??
Bo zauwazylem ze przy uzywaniu niespakowanych recordow to nic takiego nie ma, ale jak juz uzywam packed record to juz takie bledy wyskakuja. Ewentualnie jak mozna to ominac?? Zalezaloby mi na tym gdyz chcialbym aby dane zajmowaly mniej miejsca na dysku.

0

Mnie sie wydaje ze nic z tego. W pamieci to sobie moze kompilator kombinowac z packed reckord zapamietujac co i jak i kosztem predkosci oszczedzac pamiec. No ale na dysku to jak? Musialyby byc zapisyane jakies dodatkowe informacje na dysku jak taki rekord czytac. nie wiem czy to by bylo warto.
A tak od siebie dodam ze jak przeczytalem o packed recordach ze dostep do nich jest wolniejszy to odechcialo mi sie o nich dalej czytac:) Moze nieslusznie nie wiem, ale nie uzytwam ich w ogole a Twój przyklad i Twoj post utwierdzaja mnie w przekonaniu ze nie warto.

0

Po pierwsze to po zapisaniu musisz powrócić do pozycji w pliku w której zacząłeś zapisywać dane.
Kolejna sprawa to to że jeżeli zapisujesz zmienne typu ShortString (string[40]) to musi w nim znjdować się co najmniej jeden znak bo inaczej będą błędy w odczycie i zapisie.

A tak w ogóle to nie jest zbyt uniwersalny sposób zapisywania stringów do pliku, nie lepiej zrobić coś takiego:

procedure WriteString(const FS: TStream; var S: String);
var w: DWord;
    p: PChar;
begin
  w := Length(S);
  p := StrAlloc(w + 1);
  p := StrPLCopy(p, s, w);
  FS.Write(w, SizeOf(DWord));
  FS.Write(p^, w);
end;

procedure ReadString(const FS: TStream; out S: String);
var w: DWord;
    p,pTemp: PChar;
begin
  FS.Read(w, SizeOf(DWord));
  p := StrAlloc(w + 1);
  pTemp := StrAlloc(w + 1);
  try
    FS.Read(pTemp^, w);
    StrLCopy(p, pTemp, w);
    S := StrPas(p);
  finally
    StrDispose(pTemp);
    StrDispose(p);
  end;
end;

ale to tylko propozycja :d

0

To posrednictwo pchara i kopiowanie chyba jest zbyteczne. Nie proscie tak? ->

procedure WriteString(const FS: TStream;S: string);
var w: DWord;
begin
w := Length(S);
FS.write(w, SizeOf(DWord));
if w>0 then FS.write(s[1], w);
end;

Podobnie z czytaniem.

0

ale jeżelili masz zapisać string długości np. 2000 znaków to co zajmie mniej czasu, zapisanie całego ciągu "od razu" czy "dziubanie" po jednym znaku.

Do zapisywanie string-ów można uzywać jeszcze zmiennej TStringStream, to ułatwia znacznie sprawe. Wystarczy do strumienia zapisującego skopiowac zawartość zmiennej TStringStream i spokojnie zapisywać. Oczywiście najpierw zapisujemy długość stringa a potem string.

0

"Dziubnie" będzie trwało dłużej. Kiedyś to sprawdzałem. To będzie o wiele wiele dłużej trwało. Z moich doświadczeń: zapisywać na (odczytywać z) dysku (dysku) mniej razy ale większe bloki - tak jest wyraźnie szybciej.

0

Oczywiście taki kod jaki przedstawiłem wcześniej trudno bedzie przenieść do Delphi 8 ze wzgledu no zastosowanie w nim wyznaczników oraz typu PChar. Zamiast tego proponuje zastosowanie zmiennej typu TStrinStream - załadować do niej tekst a potem skopiować do strumienia głównego i po sprawie. Reszta kodu bedzie podobna do tego co napisałem.

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