Binäre Dateien
von Markus Zeichner
Übersicht
Folgend, der nun letzte Teil des Tutorials über Dateimanipulationen. Diesmal geht es um die binären Dateizugriffe. Es ist hierbei zum besseren Verständnis ratsam, vorab den Artikel über die Random-Dateien gelesen zu haben.
Mit freundlichen Grüßen
i.A. Götz Reinecke, kosti-@t-online.de
Dieses Tutorial wurde am 13.10.2007 durch Philipp Burch geringfügig überarbeitet und ergänzt.
Binärdateien öffnen
Eine Binärdatei ist eigentlich eine spezielle Form einer typisierten Datei. Die Datensatzlänge kann vom Datensatz zu Datensatz unterschiedlich sein, was alleine vom verwendeten Datentyp der Variablen abhängt. Es ist hierbei also möglich, daß der erste Datensatz in eine Variable vom Typ Long gespeichert wird, der nächste in eine Variable vom Typ Byte usw. Es werden jeweils so viele Bytes gelesen bzw. geschrieben wie die Variable groß ist. Das sollte stets im präsent sein, denn es kann schnell passieren, daß man an einer falschen Stelle der Datei versucht mit einem nicht passenden Variabelentyp Daten zu lesen bzw. zu speichern. Es kommt dabei zu keiner Fehlermeldung, man erhält jedoch falsche Werte oder im schlimmsten Falle wird die Datei teilweise unbrauchbar.
Bei den Binärdateien gibt es wie bei den typisierten Dateien kein Trennzeichen zwischen den Datensätzen, die Daten werden hintereinander in die Datei geschrieben.
"Binärdatei" ist eigentlich eine völlig falsche Bezeichnung. Binär hieße eigentlich die kleinste Speichermöglichkeit von Daten [Bit], also nur 0 oder 1 zu verwenden. Man speichert jedoch die Datei in Binärdateien nicht als einzelne Nullen oder Einsen sondern vielmehr als ganze Bytes [ein Byte besteht aus acht Bits]. Also sollten die Dateien eigentlich Bytedateien heißen, wir bleiben jedoch bei der offiziellen Bezeichnung. Um eine Binärdatei zu öffnen muss, man nicht eine höhere Schule besucht haben, es reicht lediglich dieses Tutorial aufmerksam zu lesen und den folgenden Befehl zu benutzen:
Open Dateiname For Binary As Dateinummer
Die Parameter Dateiname und Dateinummer sollten bereits bekannt sein, so daß hier keine entsprechende Beschreibung stattfindet. Wichtig ist jedoch noch, daß im Binary-Modus der Len- Abschnitt [falls mitangegeben] nicht beachtet.
Beispiel:
Dim FN As Integer FN = FreeFile Open "C:\test.txt" For Binary As FN
Listing 1
Was hat es hierbei mit dem Satzzeiger an sich?
Mit dem Seek-Befehl kann man wie bei den typisierten Dateien den Satzzeiger in der Datei bewegen bzw. die Position abfragen. Es besteht jedoch ein gravierender Unterschied den man nicht vergessen sollte:
Wird die Position bei den typisierten Dateien in Datensätzenbestimmt ist es bei den binären Dateien völlig anderes. Hier wird die Position in Bytes bestimmt! Das heißt also, daß der Datensatzzeiger bei jedem Zugriff auf die Datei, sei es schreibend oder lesend, immer um die Anzahl von Bytes verschoben wird wie die Variable groß ist. Wenn wir z.B. einen Wert aus der Datei lesen dessen Größe 1 Byte ist (eine Bytevariable) wird der Satzzeiger um eins verschoben, lesen wir jetzt einen Longwert (eine Longvariable) wird der Satzzeiger um vier verschoben, da die Longvariable vier Bytes groß ist.
Später werde ich es an einem Beispiel versuchen zur verdeutlichen.
Daten aus einer Binärdatei lesen
Hierzu nutzt man wie bei den typisierten Dateien den Get-Befehl. Die Syntax ist identisch, so daß es keine gesonderten Beschreibung nötig ist. Man sollte jedoch immer an den Byte-Satzzeiger denken. Hier möchte ich nun das angesprochene Beispiel vorstellen, an dem man das Verhalten des Satzzeigers leicht erkennen kann.
Dim Data1 As Byte Dim Data2 As Long Dim Data3() As Byte Dim FN As Integer FN = FreeFile Open "C:\Test.txt" For Random As FN Len = Len(Data2) MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data2 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data2 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Close FN ReDim Data3(9) 'Sehr wichtig, sonst liest Get nichts aus! Open "C:\Test.txt" For Binary As FN MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data2 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data2 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data1 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data1 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Get FN, , Data3 MsgBox "Satzzeiger steht an der Position: " & Seek(FN) Close FN
Listing 2
Zuerst wird eine Datei im Random-Modus [also als typisierte Datei] geöffnet und die Datensatzlänge auf die Länge von Data2 eingestellt. Danach wird die Position des Satzzeigers in eine MsgBox ausgegeben, diese sollte direkt nach dem Öffnen der Datei auf eins stehen. Jetzt wird ein Datensatz aus der Datei gelesen und der Datensatzzeiger automatisch auf den nächsten Datensatz gebracht. Dieser wird wieder in der MsgBox angezeigt. Obwohl wir vier Bytes aus der Datei gelesen haben, zeigt der Satzzeiger auf den zweiten Datensatz. Das ist bei typisierten Dateien auch richtig so.
Beim nächstem Lesen aus der Datei wird der Datensatzzeiger wieder um eins erhöht. Wir schließen jetzt die Datei und öffnen sie erneut, diesmal jedoch im binären Modus. Die MsgBox zeigt, dass der Datensatzzeiger nach dem Öffnen der Datei, wie bei den typisierten Dateien, auf eins steht. Jetzt lesen wir einen Long-Wert aus der Datei. Der Datensatzzeiger steht diesmal nicht auf zwei sondern auf fünf. Das ist völlig korrekt, ist doch eine Longvariable vier Bytes groß und 1 + 4 = 5.
Jetzt wird noch mal ein Longwert gelesen, der Satzzeiger steht dann also auf 9. Als nächstes wird ein Bytewert gelesen und der Satzzeiger um ein Byte erhöht, was 10 ergibt. Wie es in dem Code weiter geht sollte eigentlich schon jedem bekannt sein.
Am Ende wird nun noch ein ganzes Array auf einen Schlag gelesen. Hier ist zu beachten, dass das Array vor dem lesen auf die gewünschte Länge initialisiert wird, da Get sonst nicht weiss, wie viel gelesen werden muss.
Wie man bereits sehen kann, ist es nicht ohne weiteres möglich, Daten die nicht von konstanter Länge sind mitten aus der Datei zu lesen, es sei denn man merkt sich die Position an der die Daten liegen und liest diese mit der Datensatznummer aus. Sollte die Position der Daten in der Datei bekannt sein ist es empfehlenswert diese mit in den Get-Befehl einzugeben.
Noch eine Anmerkung am Rande. Sollte man unter VB 3 mit Byte-Werten gearbeitet haben (Nachbildung eines Byte as String * 1) muss man diese Definition ab VB 4 in den neuen Datentyp Byte umwandeln da mittlerweile die Deklaration String * 1 einem zwei Byte langen Wert entspricht.
In eine Binärdatei schreiben
Wie wahrscheinlich schon vermutet, geschieht dies mit dem gleichen Befehl, wie bei den typisierten Dateien. Außer der Besonderheit des Satzzeigers besteht hier überhaupt kein Unterschied. Aus diesem Grund spare ich mir eine genauere Beschreibung und komme direkt zu einem Beispiel. Bei diesem Beispiel handelt es sich um eine leicht abgeänderte Version des Programms, indem die letzte Fensterposition gespeichert und wieder gelesen werden kann, mit dem Unterschied, daß hier auch die WindowState-Eigenschaft mitgespeichert und berücksichtigt wird.
Option Explicit Private Type WindowPos x As Integer y As Integer w As Integer h As Integer End Type Public Sub Form_Load() If FileExist("WindowPrefs.dat") Then Dim FN As Integer Dim Data As Long FN = FreeFile Open "WindowPrefs.dat" For Binary As FN Get FN, , Data If Data > 3 Then Goto DatenFalsch Form1.WindowState = Data If Form1.WindowState = 0 Then Dim wp As WindowPos Get FN, , wp Me.Left = wp.x Me.Top = wp.y Me.Width = wp.w Me.Height = wp.h End If DatenFalsch: Close FN End If End Sub '... ' hier geht das Programm weiter '... Public Sub Form_Unload(Cancel As Integer) Dim FN As Integer Dim Data As Long FN = FreeFile Open "WindowPrefs.dat" For Binary As FN Data = Form1.WindowState Put FN, , Data If Data = 0 Then Dim wp As WindowPos wp.x = Me.Left wp.y = Me.Top wp.w = Me.Width wp.h = Me.Height Put FN, , wp End If Close FN End Sub ' und noch eine Funktion mit der man das Vorhandensein ' eine Datei überprüft Public Function FileExist(Dateiname As String) As Boolean On Error Goto Fehler FileExist = Dir$(Dateiname) <> "" Exit Function Fehler: FileExist = False Resume Next End Function Private Sub Command1_Click() Unload Me End Sub
Listing 3
Wie man sieht, ist es mit Put und Get auch bei binären Dateien problemlos möglich, benutzerdefinierte Typen ohne Umwege zu schreiben und zu lesen.
Wichtigste Änderungen zur letzten Version:
- Fensterdaten werden in Binärdatei gespeichert.
- Zusätzlich wird der Fensterstatus mitgespeichert.
- Wenn das Fenster geschlossen wird und es maximiert ist, werden die Fensterdaten nicht in die Datei gespeichert.
- Beim Öffnen werden die Fensterdaten nicht eingestellt, wenn das Fenster maximiert angezeigt werden soll.
So jetzt sind wir am Ende des Tutorials angelangt, kennen uns mit den drei Datenarten aus, wissen wie man die lesen und schreiben kann und was man dabei beachten soll. Jetzt möchte ich noch eins loswerden: In den Modi Binary, Input und Random kann eine Datei mit einer anderen Dateinummer geöffnet werden, ohne sie zuvor schließen zu müssen. In den Modi Append und Output muss eine Datei immer erst geschlossen werden, bevor sie mit einer anderen Dateinummer geöffnet werden kann.
Nun steht das Tutorial zur Diskussion. Fragen, Anregungen, Korrekturen können ins Forum gepostet werden die dann von allen besprochen werden können oder ihr könnt mir auch mailen.
Komplettes Tutorial als PDF-Datei [479000 Bytes]
Ihre Meinung
Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.