Home » Tutorials » Datenspeicherung » Binäre Dateien

Binäre Dateien

TKontakt.SaveToBinaryTag

Jeder Kontakt soll selbst in der Lage sein seine Daten in dem Zwischenformat abzulegen. Dazu wird die Klasse um die Methode SaveToBinaryTag erweitert.

TKontakt = class
  ...
  public
  ...
    procedure SaveToBinaryTag(Tag: TRakBinaryTag);
  ...
  end;


procedure TKontakt.SaveToBinaryTag(Tag: TRakBinaryTag);
begin
  if Vorname <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'Vorname', Vorname);
  if Nachname <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'Nachname', Nachname);
  if Email <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'Email', Email);
  if TelArbeit <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'TelArbeit', TelArbeit);
  if Strasse <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'Strasse', Strasse);
  if Handy <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'Handy', Handy);
  if TelPrivat <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'TelPrivat', TelPrivat);
  if Ort <> '' then
    TRakBinaryShortString.AddToTag(Tag, 'Ort', Ort);

  if not Privat then
    TRakBinaryBoolean.AddToTag(Tag, 'Privat', Privat);

  if not FGeburtstagNichtVersorgt then
    TRakBinaryDateTime.AddToTag(Tag, 'Geburtstag', Geburtstag);

  if not FPLZNichtVersorgt then
    TRakBinaryLongint.AddToTag(Tag, 'PLZ', PLZ);

  if Bild.Graphic <> nil then
    TRakBinaryPicture.AddToTag(Tag, 'Bild', Bild.Graphic);
end;

Hier werden alle Daten in den Knoten Tag eingehängt.
Da wir nicht unnötig Plattenplatz verschwenden wollen, speichern wir nur die Daten, die nicht ihren Defaultwert haben.

if Vorname <> '' then

Bei Vorname ist der leere String der Defaultwert.

TRakBinaryShortString.AddToTag(Tag, 'Vorname', Vorname);

Damit fügen wir den Vornamen dem Tag hinzu. Es wird hier nicht wieder ein Unterknoten erzeugt, da ein Knoten selbst nicht direkt Daten speichern kann. Dies können nur die sogenannten Attribute. Hier wird also ein Attribut hinzugefügt. Ein Attribut wird durch eine spezielle Klasse repräsentiert. Eine solche Klasse muss direkt oder indirekt von TRakBinaryAttribute abgeleitet sein. TRakBinaryAttribute findet man in der Unit RakBinaryStreamData. Im Gegensatz zu Knoten müssen Attribute, die zum selben Knoten gehören, einen eindeutigen Namen haben.
Hier verwenden wir die Klasse TRakBinaryShortString. Mit Attributen dieser Klasse kann man ShortStrings speichern, also Strings mit einer Länge bis zu 255 Zeichen. Wir rufen hier dessen Klassenmethode AddToTag auf. Diese Methode erzeugt eine Instanz von TRakBinaryShortString, versorgt dessen Property ItemName mit dem Wert ‚Vorname‘ und dessen Property Value mit dem Vornamen.
Wir hätten den Einzeiler auch etwas ausführlicher schreiben können. Die folgenden Zeilen machen genau das Gleiche wie der Einzeiler.

var
  Attr: TRakBinaryAttribute;
  ShortStringAttr: TRakBinaryShortString;
begin
  Attr := Tag.AddAttribute(TRakBinaryShortString, 'Vorname'));
  ShortStringAttr := Attr as TRakBinaryShortString;
  ShortStringAttr.Value := Vorname;

Aber auch hier wird das Erzeugen der Instanz von TRakBinaryShortString durch eine Methode erledigt.
Da wir tippfaul sind, bleiben wir natürlich bei der Einzeilertechnik.

if not Privat then

Bei den Boolean-Wert nehmen wir true als den Defaultwert an, also speichern wir ihn nur, wenn er false ist.

TRakBinaryBoolean.AddToTag(Tag, 'Privat', Privat);

Da wir uns nicht mit einer Konvertierung in einen String belasten wollen, nehmen wir hier nicht TRakBinaryShortString, sondern TRakBinaryBoolean. Ansonsten ist es genau das gleiche wie bei TRakBinaryShortString.

TRakBinaryDateTime.AddToTag(Tag, 'Geburtstag', Geburtstag);

Für TDateTime gibt es auch wieder eine eigene Klasse, nämlich TRakBinaryDateTime.
Es gibt für fast jeden Delphityp eine Klasse. Was man vergeblich suchen wird, sind Klassen für integer und float. Bei diesen beiden Typen ist die Größe des benötigten Speicherplatzes nicht sicher. Bei Delphi 5 und Delphi 6 benötigt ein integer 4 Byte. Bei Delphi 1 war ein integer noch 2 Byte groß. Sobald es ein Delphi für 64-Bit-Prozessoren gibt, wird ein integer wahrscheinlich 8 Byte groß sein. Mit float verhält es sich ähnlich. Statt dessen sollte man Longint und Double verwenden.
Für String gibt es auch keine Klasse, da eine Compilerdirektive festlegt, was String tatsächlich ist. Hier muss man sich für ShortString oder AnsiString entscheiden.
Interessant ist dann noch das Speichern des Bildes. Hier wird ja nicht mit einen der grundlegenden Datentypen von Delphi gearbeitet, sondern mit der Klasse TPicture. Alle von TGraphic abgeleiteten Klassen können von TPicture verwaltet werden. Dies sind z.B. die Klassen TBitmap oder TJPEGImage. Diese enthalten ein Bild, was bedeutet, dass sie binäre Daten in einem speziellen Format enthalten.
Wenn man es mit binäre Daten eines speziellen Formats zu tun hat, dann kann man zum Speichern die Klasse TRakBinaryBlob verwenden. Falls man mit derartigen Daten immer wieder arbeitet, dann kann man sich von TRakBinaryBlob eine eigene Klasse ableiten, die einem den Umgang damit erleitert. Ein Beispiel für eine derartige Klasse ist TRakBinaryPicture. Da man häufig mit Bildern, also mit TBitmap & Co. arbeitet, enthält die Unit RakBinaryStreamData bereits die Klasse TRakBinaryPicture, die es einem besonders leicht macht Bilder zu speichern.

if Bild.Graphic <> nil then
    TRakBinaryPicture.AddToTag(Tag, 'Bild', Bild.Graphic);

Wir speichern nur etwas, wenn wir tatsächlich ein Bild haben.
Dank der Klasse TRakBinaryPicture ist das Speichern eines Bildes genauso einfach wie das Speichern eines Strings.
Damit haben wir einen kompletten Kontakt in das Zwischenformat übersetzt.
Damit die Dateien weniger Speicherplatz benötigen, hätten wir hier kürzere Namen für unsere Attribute verwenden können. Statt

TRakBinaryShortString.AddToTag(Tag, 'TelArbeit', TelArbeit);

hätten wir z.B.

TRakBinaryShortString.AddToTag(Tag, 'TA', TelArbeit);

schreiben können. Zwecks der besseren Lesbarkeit nehmen wir aber die langen speicherfressenden Namen.