Einführung in das Programmieren mit DELPHI  

23. Binäre Dateien

In DELPHI bzw. PASCAL haben wir es im Wesentlichen mit drei Arten von Dateien zu tun:

  1. Text-Dateien

    Auf ihre Daten greift man am Besten mit den Methoden LoadFromFile bzw. SaveToFile einer Stringliste, z.B. Memo.Lines oder ListBox.Items, zu.
    (siehe: 16. Der Sudoku-Assistent: Lösung, dort die Prozeduren BtnLadenClick und BtnSpeichernClick)

  2. Record-Dateien

    Um auf ihre Daten zuzugreifen, wird eine Dateivariable als File of Records deklariert. Diese wird durch AssignFile mit einer Datei verknüpft und die Datensätze werden mit Read aus der Datei gelesen bzw. mit Write in die Datei geschrieben.
    (siehe: 23. Record-Dateien)

  3. Binäre Dateien

    Binäre Dateien sind untypisierte Dateien. Die Dateivariable wird daher nur als File ohne Datentyp deklariert, die Verknüpfung der Dateivariablen mit einer Datei erfolgt wie bei den Record-Dateien durch AssignFile.
    Gelesen und geschrieben wird blockweise mit BlockRead und BlockWrite. Dazu muss vorher ein Buffer, d.h. ein array of byte deklariert werden.
    Die Größe der Datenblöcke wird als zweiter Parameter bei Reset und Rewrite angegeben. Bei BlockRead wird angegeben, wie viele Blöcke in den Buffer gelesen werden sollen. Ein vierter, optionaler Parameter gibt an, wie viele Blöcke tatsächlich gelesen wurden.

    AssignFile(Dateivariable,Dateiname)Verbindet eine Datei mit der im Programm deklarierten Dateivariablen
    Reset(Dateivariable, Blockgröße)Öffnet eine bestehende Datei
    Rewrite(Dateivariable, Blockgröße) erzeugt eine neue Datei
    Seek(Dateivariable,Blocknummer)Setzt den Dateizeiger auf einen bestimmten Datenblock
    BlockRead(Dateivariable, Buffer, n1, [n2])Liest n1 Datenblöcke aus der Datei in den Buffer
    BlockWrite(Dateivariable, Buffer, n1, [n2])Schreibt n1 Datenblöcke aus dem Buffer in die Datei
    Truncate(Dateivariable)Schneidet alle folgenden Datenblöcke ab
    CloseFile(Dateivariable)Schließt eine Datei
      
    FileSize(Dateivariable)Liefert die Anzahl der Datenblöcke in einer Datei
    FilePos(Dateivariable)Liefert die Nummer des aktuellen Datenblocks
    Eof(Dateivariable)Ist True wenn das Dateiende erreicht ist
    FileExist(Dateiname)Ist True wenn die Datei vorhanden ist

     

    Beispiel: FileCopy

    Mit der folgenden Prozedur wird eine beliebige Datei byteweise (Blockgröße=1) eingelesen und eine Kopie davon wieder gespeichert.

    procedure TForm1.FileCopy(const InputFilename, OutputFilename: string);
    var
      InputFile,  OutputFile: File;
      AnzGelesen, AnzGeschr : Integer;
      Buffer: array[1..2048] of Byte;
    begin
      AssignFile(InputFile, InputFilename);
      Reset(InputFile, 1);
      AssignFile(OutputFile, OutputFilename);
      Rewrite(OutputFile, 1);
      repeat
         BlockRead (InputFile,  Buffer, SizeOf(Buffer), AnzGelesen);
         BlockWrite(OutputFile, Buffer, AnzGelesen,     AnzGeschr);
      until (AnzGelesen = 0) or (AnzGelesen <> AnzGeschr);
      CloseFile(InputFile);
      CloseFile(OutputFile);
    end;
    

     

    procedure TForm1.Button3Click(Sender: TObject);
    begin
      FileCopy(Edit1.Text,Edit2.Text);
    end;
    

     

    Beispiel: HexView

    Als untypisierte Dateien lassen sich alle beliebigen Dateien laden. Eine gängige Methode ist die gemischte Darstellung als Hexadezimalzahlen und ASCII-Text.
    Meistens kann man an den ersten Bytes einer Datei, dem sog. Header, den Dateityp ablesen. Ein HexViewer ist schnell geschrieben.

    procedure TForm1.btnOpenClick(Sender: TObject);
    var datei: File; b: TBuffer; n:integer;
    begin
      Memo1.Font.Name := 'Courier New';
      Memo1.Clear;
      if OpenDialog1.Execute then
        begin
          Edit1.Text := OpenDialog1.Filename;
          AssignFile(datei,OpenDialog1.Filename);
          Reset(datei,1);   // Blockgröße = 1 Byte
          repeat
             BlockRead(datei, b, SizeOf(b), n);
             Memo1.Lines.Add(BufferToLine(b,n));
          until eof(datei);
        end;
    end;
    
    function TForm1.BufferToLine(b:TBuffer; n:integer):string;
    var i:integer; s1,s2:string;
    begin
       s1 := '';    // String aus Hexadezimalzahlen
       s2 := '';    // String aus ASCII-Zeichen
       for i := 1 to n do
          begin
            s1 := s1 + Format('%2.2x ', [ b[i] ]);
            if b[i]>31 then
               s2 := s2 + char(b[i])
            else
               s2 := s2 + '.';
          end;
       result:= Format('%-96s    %-32s', [s1,s2]);
    end;
    

     

    Die Zeichenkombination 0D 0A, die wiederholt vorkommt, besteht aus den beiden Steuerzeichen CR (Carriage Return) und LF (Line Feed), die einen Zeilenumbruch bewirken.

    © 2009 : Bernd Schultheiss