Arbeiten mit Dateien

CP/M bietet eine Vielzahl von Funktionen zum Arbeiten mit Dateien. Die Ein/Ausgabe-Funktionen basieren alle auf der Einheit eines Rekords - also eines Blocks mit einer Länge von 128 Bytes. Oft möchte man jedoch - so wie z.B. bei der Ein/Ausgabe mit den Konsolfunktionen - nicht einen gesamten Block sondern ein einzelnes Zeichen (Byte) bearbeiten. An dieser Stelle habe ich einige Routinen zum Thema Dateiverarbeitung ausgehängt. Die meisten der angegebenen Routinen stammen aus meiner eigenen Bibliothek.

Byte Ein/Ausgabe
Datei erweitern
Datei positionieren
Dateioperation bei Suchfunktion

Byte Ein/Ausgabe

Wie oben ausgeführt ist die Basis zum Arbeiten mit Dateien der Rekord mit einer Länge von 128 Bytes. Will man auf Byte-Ebene programmieren, so ist eine eigene Routine notwendig, in der ein eigener Zeiger innerhalb des Rekords verwaltet wird. Diese kann z.B. so aussehen:
Lesen aus einer Datei
  • Laden des Zeigers
  • Testen, ob dieser den Wert 128 hat
  • Wenn ja, dann -
    • Zeiger auf 0 setzen
    • Nächsten Rekord der Datei lesen
  • Zeiger zur Rekordadresse addieren
  • Byte aus dieser Adress-Kombination laden
  • Zeiger um 1 erhöhen
  Nach dem erfolgreichen Öffnen der Datei muss der Zeiger auf den Wert 128 gesetzt werden, womit vor dem Lesen des ersten Zeichens ein Lesen des ersten Rekords erzwungen wird.

Nicht aufgeführt ist hier die Überprüfung des Dateiendes. Dieses ist bei einer binären Datei das physikalische Ende der Datei, bei einer Textdatei das Zeichen für „End of File" (0x1AH, ^Z).
Beispiel zum Lesen aus einer beliebigen Datei   Beispiel zum Lesen aus einer Textdatei
Schreiben in eine Datei
  • Zeiger zur Rekordadresse addieren
  • Byte in diese Adress-Kombination speichern
  • Zeiger um 1 erhöhen
  • Testen, ob Zeiger den Wert 128 hat
  • Wenn ja, dann -
    • Zeiger auf 0 setzen
    • Diesen Rekord in die Datei schreiben
  Nach dem erfolgreichen Anlegen der Datei muss der Zeiger auf den Wert 0 gesetzt werden, womit ein leerer Rekord angezeigt wird.

Soll eine Textdatei geschlossen werde, so muss der reguläre Text mit „End of File" (0x1AH, ^Z) beendet werden.
Beispiel zum Schreiben in eine beliebige Datei   Beispiel zum Beenden einer beliebigen Datei

Datei erweitern

Es gibt Fälle, wo Daten als Protokoll in eine einzige Datei geschrieben werden sollen. Das kann bedeuten, dass an eine bestehende Datei weitere Daten angehängt werden sollen. Eine BDOS-Funktion „APPEND" gibt es nicht, lediglich „OPEN" (Öffnen einer bestehenden Datei) und „CREATE" (Anlegen einer neuen Datei). Der einfachste Fall wäre, die bestehende Datei in eine neue Datei umzukopieren und daran neue Daten anzuhängen. (Wobei ein notwendiges Umbenennen und Löschen hier nicht erwähnt werden soll). Bei großen Datenmengen muss hier neben dem Zeitfaktor für das Kopieren auch der benötigte Speicherplatz für zwei Dateien berücksichtigt werden. Eine andere Möglichkeit wird nun vorgestellt.
Anhängen an eine Datei
  • Öffnen der Datei
  • Testen, ob diese vorhanden ist
  • Wenn JA, dann -
    • Länge der Datei bestimmen
    • Länge -1 setzen
    • Random Rekord mit diesem Wert setzen
    • Diesen Random Rekord lesen
    • Im Lesepuffer nach dem Wert 0x1AH suchen
    • Diesen Wert als Zeiger setzen
  • Wenn NEIN, dann -
    • Neue Datei anlegen
    • Zeiger auf Null setzen
  • Zeichen wie oben beschrieben in Datei schreiben
Hier eine Routine aus meiner Bibliothek und hier als Beispiel aus meiner TURBO-PASCAL Erweiterung

Datei positionieren

Textdateien, also Dateien mit variabler Rekord-Länge sind, was die Positionierung angeht, schwierig zu handhaben. Unter Unix und C sind die Funktionen fseek und ftell bekannt, die die Adresse eines Bytes innerhalb einer Datei verwalten.
ftell fseek

 
Diese Funktion ermittelt die Position eines Bytes innerhalb einer sequentiellen Datei.   Diese Funktion stellt die Position eines Bytes innerhalb einer sequentiellen Datei wieder her.
  • Ermitteln der Rekordnummer
  • Rekordnummer -1 setzen
  • Im Lesepuffer nach dem Wert 0x1AH suchen
  • Diesen Wert als Zeiger setzen
  • Zeiger und Rekordnummer sind das Resultat
 
  • Zeiger setzen
  • Rekordnummer setzen
  • Diesen Random Rekord lesen
(In den Beispielen wird der Zeiger nicht bearbeitet.)
Beispiel zum Ermitteln der Dateiposition   Beispiel zum Einstellen der Dateiposition

Eine andere Möglichkeit zur Festlegung der Dateiposition ohne die Rekordnummer lässt sich wie folgt durchführen (hier ohne die Ermittlung des Zeigers):
ftell alternativ fseek alternativ
  • Ermitteln des aktuellen Rekords
  • Ermitteln des aktuellen Extents
  • Rekord -1 setzen
  • Falls Rekord < 0:
    • Rekord auf 0x80 setzen
    • Extent -1 setzen
  • Extent und Rekord sind das Resultat
 
  • Rekord setzen
  • Extent setzen
  • Datei mit diesen Werten öffnen
  • Sequentiellen Rekord lesen
Beispiel zum Ermitteln der Dateiposition   Beispiel zum Einstellen der Dateiposition

Dateioperation bei Suchfunktion

Oft kommt es vor, dass mehrere Dateien verarbeitet werden sollen (über Joker im Dateinamen, * und ?). Zur Behandlung solcher Joker stehen die BDOS-Funktionen Search_for_first und Search_for_next zur Verfügung. Damit kann nach Dateien gesucht werden. Allerdings darf keine der anderen Datei-Operationen zwischen den Aufrufen der Suchfunktionen ausgeführt werden. Zur Lösung dieses Problems gibt es drei Möglichkeiten.
  1. Das Speichern aller gefundenen Dateinamen. Danach werden diese dann nacheinander geladen und verarbeitet.
  2. Eine trickreiche Routine aus Irv Hoffs Programm FIND54.
  3. Das Zwischenspeichern von Daten aus dem System Control Block.
Die ersten beiden Methoden gelten für alle CP/M-Versionen, die dritte nur für CP/M PLUS. Nur die erste Methode erlaubt ein Sortieren, so dass Dateien in alphabetischer Reihenfolge verarbeitet werden können. Die Aufrufe halten die Maske jeweils in „FCB".
Methode 1Methode 2Methode 3
  1. Speicheradresse laden
  2. Search_for_first(FCB)
  3. Wenn Resultat=255 dann keine Datei gefunden
  4. Gefundenen Dateinamen abspeichern
  5. Search_for_next
  6. Wenn Resultat<>255 dann weiter bei 4
  7. (Optional Dateinamen sortieren)
  8. Speicheradresse laden
  9. Nächsten Dateinamen laden
  10. (Dateioperation durchführen)
  11. Wenn mehr Dateien vorhanden, dann weiter bei 9
  1. intern_FCB=FCB
  2. FCB_Maske=FCB
  3. Search_for_first(intern_FCB)
  4. Wenn Resultat=255 dann keine Datei gefunden
  5. Such_FCB=gefundene_FCB
  6. intern_FCB=gefundene_FCB
  7. (Dateioperation durchführen)
  8. intern_FCB=Such_FCB
  9. Search_for_first(intern_FCB)
  10. intern_FCB=FCB_Maske
  11. Search_for_next
  12. Wenn Resultat<>255, dann weiter bei 5
  1. Search_for_first(FCB)
  2. Wenn Resultat=255 dann keine Datei gefunden
  3. Wenn Resultat=255 dann Ende
  4. gefundene_FCB abspeichern
  5. Werte aus SCB abspeichern
  6. (Dateioperation durchführen)
  7. Werte in SCB zurückschreiben
  8. Wenn gefundene_FCB im SCB, dann gefundene_FCB in SCB kopieren
  9. Search_for_next
  10. Weiter bei 3
(In den Beispielen werden nur die Routinen zum Suchen dargestellt.)
Beispiel Beispiel Beispiel

Letzte Änderung: 11.Februar 2003