Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Unpacked-Record und FileStream


Master_of_Magic - Fr 23.06.06 15:27
Titel: Unpacked-Record und FileStream
Ich habe einen Record in meinem Programm:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
type
  TPlaneten = Record //224
    Name:string[20]; //21
    X: Word; //2
    Y: Word; //2
    Z: Byte; //1
    Buildlevel: array[0..12of byte; //13
    Solarsats: Word; //2
    Temperatur: shortint; //1
    Stempelbestand: array[0..2of Cardinal; //12
    HPStempelbestand: array[0..2of Cardinal; //12
    Stempelzeitpunkt: TDateTime; //8
    Benutzerprojekte: array[0..11of Cardinal; //48
    Schiffsanzahl: array[0..17of Word; //36
    Verteidigungsanzahl: array[0..9of Word; //20
    Wirtschaftseinstellungen: array[0..5of Byte; //6
    Buildbenachrichtigungen: array[0..13of boolean; //14
    Schiffsbenachrichtigungen: array[0..18of boolean; //19
    Verteidigungsbenachrichtigungen: array[0..10of boolean; //11
  end;
  TAccount = Record
    Planet: array[0..12of TPlaneten;
    Forschungslevel: array[0..19of Byte;
    Forschungsprozente: array[0..19of Byte;
    Forschungsbenachrichtigungen: array[0..20of boolean;
    Urlaubsrechnerdaten: array[0..70of Cardinal;
    Urlaubsrechnerzeiten: array[0..9of TDateTime; //Länge 19 (Datum+Uhrzeit)
    Servershift: TDateTime;
    Umodestart: TDateTime; //8
  end;

var
  Account:Array[0..10of TAccount;


Mit dem Record arbeite ich während der Programmnutzung und beim Beenden wird er über Streamname.WriteBuffer(Account,SizeOf(Account));
gespeichert und entsprechend geladen.

Wie das halt so ist, wenn man nicht vorrausschauend programmiert, bekommt man irgendwann ein Problem: Ich kann nun das Array of Record nicht mehr als Ganzes laden, sondern muss dir einzelnen Record-Felder per Streamname.Read(var,SizeOf(var));
auslesen.

Dies funktioniert aber nicht so richtig, da der Record ja nicht packed ist. Daher hab ich drei Fragen dazu:

1. Gibts 'ne elegante Möglichkeit, einen Nicht-packed-Record mit Read auszulesen? Mein RF-Alignment ist 8.

2. Lohnt sich packed immer, auch wenn ständig auf die Daten zugegriffen wird? Ich habe gehört, es soll langsamer sein - gibts da konkrete Messewerte?.

3. Gibt es eine Möglichkeit, den Record packed zu speichern und damit per Stream.Read auslesen zu können - ihn jedoch nicht packed im Speichern zu haben?)

Und sorry für drei Fragen in einem Thread, aber es ist ja dasselbe Thema und gehört zu meinem Record. Da wollte ich nicht dreimal dasselbe posten ... ;-)


Bernhard Geyer - So 25.06.06 21:56

zu 1: Elegant weis ich nicht, aber du wirst mit TFilestream byteweise die Daten auslesen müssen

zu 2: Für Meßwerte: Selbst ist der Mann. Schleife mit 1 Mio Zugriffen auf jedes Element des Records. Einmal als Packed und einmal nicht

zu 3. Definiert dir 2 Typen. Einmal Packed und einmal nicht + Hilfsfunktionen um Record von Packed nach Unpacked zu kopieren und umgekehrt.


BenBE - So 25.06.06 22:11

Da deine Records keine Varianten Typen (Strings) enthalten, kannst Du ohne Weiteres jeden Account einfach mit FS.ReadBuffer(Account[X], SizeOf(TAccount)); auslesen ... Das hier ein ShortString enthalten ist, stört nicht, da diese anders verwaltet werden und damit kaum Compiler-Magic brauchen (und Inline gespeichert werden).


jasocul - Mo 26.06.06 08:17

Der Geschwindigkeitsunterschied ist normalerweise zu vernachlässigen.
Interessant wird es erst, wenn du viel im Hauptspeicher mit den Records hantierst. Zum Beispiel durch ständiges Umsortieren. Und auch dann merkt man das vermutlich erst, bei ein paar tausend Datensätzen.
Wenn du die Records nur zur Datenhaltung benötigst oder es sowieso nur einer ist, dann ist das zu vernachlässigen. Das Einlesen der Records von der Festplatte ist erheblich langsamer als die Verwaltung im Speicher.


Master_of_Magic - Do 29.06.06 19:00

@Bernhard Geyer
zu 1. Ich hab die Daten jetzt normal ausgelesen und die nicht genutzten Bereiche mit

Delphi-Quelltext
1:
stream.position:=stream.position+X;                    

übersprungen ... das geht auch, ist nur etwas aufwändig herauszufinden ;-)

zu 2. Ich hab das gerade mal gemacht und die Abweichung bei Lesezugriffen auf das erste Element der Arrays bzw. jedes Element des Records errechnet. Ergebnis:
Mein packed Record ist ca. 1% schneller! :roll:

zu 3. Hast du mir für die Deklaration einen Code-Schnipsel? Weil ich weiß nicht recht, wo ich das packed hinschreiben soll ... oder muss ich den kompletten Record zwei mal schreiben?

@BenBE
Das geht nicht, da in der Datei der Record ja unpacked, im Programm jedoch jetzt packed ist. Dein Vorschlag liefert in dem Fall ja Fehler. Aber ich hab ja jetzt 'ne Lösung gefunden (siehe zu 1.)

@jasocul
Ja, das habe ich nun auch gemerkt. Vorallem ist die Verwaltung mit Streams einfacher ...
Letztendlich macht es bei meiner Anwendung 1,8KB Platzersparnis und kaum einen Geschwindigkeitsunterschied aus. :wink:


Dann danke ich für eure Antworten, meine Frage ist damit geklärt. Packed ist also immer sinnvoll, wenn ich den Record abspeichere und keine rechenintensiven Operationen mit ihm durchführen muss...