Working with files

CP/M offers a number of functions for working with files. The input/output functions base upon a length of a record - i.e. a block consisting of 128 bytes. In many cases a character (byte) base i/o is preffered instead of a block - e.g. such as the i/o using a console. Find here some routines for working with files. Most of them are used in my own library.

Byte Input/Output
Append files
Position files
Searching for files

Byte Input/Output

As remarked above working with files bases upon a record size of 128 bytes. For working on a byte base it is necessary to use a procedure handling a pointer within a record. It could look like this:
Reading from a file
  • Load the pointer
  • Test if its value is 128
  • If yes, then -
    • Reset pointer to 0
    • Read next record from file
  • Add pointer to address of record
  • Load byte from this combined address
  • Increment pointer by 1
  After succesfull opening the file the pointer must be set to 128. This forces a record to be read before reading a character.

Not discussed here is the methode for checking the end of a file. Handling a binary file this corresponds to the physical end of file, handling a text file the „End of File" character (0x1AH, ^Z) defines the state.
Sample for reading a byte from any file   Sample for reading a character from a text file
Writing into a file
  • Add pointer to address of record
  • Store byte into this combined address
  • Increment pointer by 1
  • Test if its value is 128
  • If yes, then -
    • Reset pointer to 0
    • Write this record into the file
  After succesfull creating the file the pointer must be set to 0. This indicates an empty record.

Closing a text file requires a final „End of File" character (0x1AH, ^Z) to be written to the file.
Sample writing a byte into any file   Sample writing a character into a text file

Append files

Sometimes a single file is used for logging multiple events. This may imply appending data onto an existing file. A BDOS funktion „APPEND" does not exist, merely „OPEN" (open existing file) and „CREATE" (creating a new file). The most simple way for doing an append would be to copy an existing file to a new one and proceed writing new data to that file. (Of course it implies deleting an existing file and rename the file to the original one).

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

Position files

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

Searching for files

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