Magic Disk 64

home to index to text: MD9206-KURSE-FLOPPY-KURS_1-A.txt
  Floppy-Kurs: "Es rappelt in der Kiste"
                 (Teil 2)               

Hallo zum zweiten Teil des Floppy-Kurses. In der vorletzten MD hatten einiges über den Floppybefehlskanal und die Programmierung sequentieller Files gelernt. In diesem Teil wollen wir uns nunmehr mit der relativen Dateiverwaltung beschäftigen, die zwar etwas komplizierter zu programmieren, dafür aber weitaus flexibler als die sequentielle Dateiverwaltung zu handhaben ist.

DIE RELATIVE DATENVERWALTUNG            

Im ersten Teil des Floppy-Kurses hatten wir bei den von der Floppy unterstützten Filetypen auch die sogenannten REL-Files besprochen. Sie bezeichnen Dateien, die einen RELativen Aufbau haben. Was das bedeutet wollen wir nun klären.
Sicherlich erinnern Sie sich, daß die sequentiellen Files, wie der Name schon sagt Daten " sequentiell", also Byte hinter Byte enthalten. Wenn wir Daten in einem solchen File gespeichert hatten, so mussten wir immer das komplette File in den Rechner einlesen, um die Daten weiterverwnden zu können. Bei relativen Files ist dieser Aufbau nun anders geregelt. Sie arbeiten mit sogenannten " Datensätzen", oder engl." Records" . Im Prinzip kann man eine relative Datei mit einem externen Variablenfeld vergleichen. Wir geben der Floppy lediglich an, daß wir z. B. das 24 . Element ( sprich:
Record) ansprechen wollen, und schon können wir es lesen oder schreiben. Bei einem sequentiellen File hätten wir die 23 Eintragungen vorher erst überlesen müssen, bis wir auf das gewollte Element hätten zugreifen können.
Die Vorteile von REL-Files liegen damit auf der Hand:
1) Schnellerer Zugriff, da wir nur die benötigten Daten ansprechen müssen.
2) Speicherersparnis im Rechner selbst, da alle Daten extern gelagert sind und kein Speicherplatz mit momentan nicht benötigten Daten belegt wird.
Jedoch hat die relative Dateiverwaltung auch einen Nachteil: da sie von BASIC aus nicht unterstützt wird, ist ihre Programmierung relativ umständlich. Dennoch lässt sich auch das lernen, und wer es einmal kann der wird merken, daß die Vorteile überwiegen.

DIE PROGRAMMIERUNG                      

Bevor wir überhaupt irgendetwas aus oder in ein relatives File lesen oder schreiben können müssen wir es erst einmal generieren. Öberhaupt wird ein relatives File ganz und gar anders behandelt als ein sequentielles. So wird beim Üffnen nicht mehr zwischen " Lesen" und " Schreiben" unterschieden. Wir öffnen ein solches File ganz einfach um der Floppy anzuzeigen, daß wir es nun benutzen wollen. Ob wir nun lesen oder schreiben ist ganz egal. Die Floppy erkennt automatisch, wenn wir etwas schreiben oder lesen. Das heißt also, daß wir bei der Benutzung eines relativen Files immer auch den Floppybefehlskanal öffnen müssen. Öber spezielle Befehle wird die Floppy dann über die folgende Operation informiert. Sie stellt dann, je nach Befehl, beim Lesen auf dem relativen Filekanal die gewünschten Daten bereit, bzw. erwartet auf diesem die Daten, die geschrieben werden sollen.
Wollen wir nun also einmal ein relatives File anlegen, damit wir es benutzen können. Bevor wir das tun, sollten wir uns überlegen, wie lang ein Datensatz unseres REL-Files werden soll, und wie viele davon wir vorläufig darin speichern wol- len. Ersteres müssen wir deshalb tun, weil die Datensätze eines relatives Files immer gleich lang sein müssen, um der Floppy das Auffinden eines Datensatzes zu ermöglichen. Nehmen wir einfach einmal an, daß wir 300 Datensätze zu je 80 Zeichen anlegen wollen. Wie oben schon erwähnt, öffnen wir zuerst einmal den Floppybefehlskanal. Anschließend folgt der OPEN-Befehl für das relative File. Wir legen dabei wie gewohnt die logische Filenummer, die Gerätenummer und die Sekundäradresse fest, und geben einen Namen für unsere Datei an. An diesen angehängt folgt die Typenkennung ", L," sowie der Länge des Datensatzes in diesem File. Hier ein kleiner Hinweis: im ersten Teil dieses Kurses erwähnte ich, daß die Kennung für eine relative Datei beim Öffnen ein " R" ist.
Das war leider eine Fehlinformation!" L" ist die richtige Bezeichnung für den OPEN-Befehl!
Hier nun ein Beispiel, in dem wir das relative File " TEST" mit 80 Zeichen pro Datensatz eröffnen:

OPEN 1,8,15                             
OPEN 2,8,3,"TEST,R,"+CHR$(80)           

Der Befehlskanal hat nun die logische Filenummer "1", das relative File die "2" . Wichtig beim Üffnen desletzeren ist auch die Wahl der Sekundäradresse, da diese bei der Befehlsübergabe an den Befehlskanal verwendet wird. Wählen Sie bei der Sekundäradresse bitte nicht die vorreservierten Nummern 0,1 und 15( sh.
Floppy-Kurs, Teil 1), sondern nur Nummern zwischen 2 und 14 . Nachdem wir nun also alles geöffnet hätten, was wir benötigen, müssen wir jetzt erst einmal die gewünschten 300 Datensätze in der REL-Datei anlegen. Das funktioniert eigentlich ganz einfach: wir sprechen lediglich mit einem speziellen Befehl den 300 . Datensatz an, und schreiben den Wert 255 hinein. Die Floppy generiert in diesem Fall nämlich automatisch alle fehlenden Datensätze - in unserem Beispiel also alle 300 . Das Generieren dieser Sätze kann jetzt einige Zeit in Anspruch nehmen, da die Floppy nun den Speicherplatz, den sie für alle Sätze braucht, automatisch belegt und mit den Bytewerten 255 füllt. Stören Sie sich bitte nicht daran, wenn während dieses Arbeitsgangs ( wie auch bei allen anderen Operationen mit relativen Files) die Floppy-LED zu blinken beginnt, oder trotz Zugriffs zeitweise erlischt. Das ist ganz normal bei der Arbeit mit relativen Files.
Wenn die Floppy mit dem Anlegen der relativen Datei fertig ist blinkt sie übrigens sowieso, da wir durch den Zugriff auf einen noch nicht existierenden Datensatz einen " Record not present"- Fehler erzeugt haben, der uns jedoch nicht weiter stören soll. Durch Auslesen des Befehlskanals stoppen wir das LED-Blinken. Hier nun das Ganze als Programm.

10 OPEN 1,8,15                          
20 OPEN 2,8,3,"TEST,R,"+CHR$(80)        
30 HI=INT(300/256): LO=300-256*HI       
40 PRINT#1,"P"+CHR$(3)+CHR$(LO)+CHR$(HI)
   +CHR$(1)                             
50 PRINT#2,CHR$(255)                    
60 INPUT#1,A,B$,C,D:                    
70 PRINT A,B$,C,D                       
80 CLOSE1: CLOSE2                       

Die OPEN-Befehle aus den Zeilen 10 und 20 kennen wir ja schon. In Zeile 30 spalten wir die Zahl 300( die Anzahl der Datensätze, die wir in unserer Datei verwenden möchten) in Lowund High-Byte auf, da mit dem CHR$- Befehl ja immer nur 8- Bit-Werte ( von 0 bis 255) übergeben werden können, und durchaus mehr Datensätze möglich sein können, müssen wir einen 16- Bit-Wert in Lo/ Hi-Folge an die Floppy senden. Dies geschieht in der folgenden Zeile - mit dem ersten PRINT#- Befehl senden wir den Positionierungsbefehl an die Floppy. Wohlgemerkt geschieht dies über den Befehlskanal!
Aus dem Beispiel ist die Syntax des Positionierungsbefehls ersichtlich. Beginnend mit dem Zeichen " P"( für " positionieren") werden in Reihenfolge die Sekundäradresse der REL-Datei auf die sich die Positionierung beziehen soll, die Datensatznummer in Lo/ Hi-Folge, sowie die Byteposition innerhalb des entsprechenden Datensatzes mittels CHR$- Codes an die Floppy übermittelt. In Zeile 50 wird nun über den logischen Kanal des REL-Files der Wert 255 in den positionierten Datensatz geschrieben. Da er, wie alle anderen vor ihm, noch nicht existiert, beginnt die Floppy nun damit alle Datensätze anzulegen, um den Schreibbefehl in Record 300 ausführen zu können. Es ist übrigens wichtig, daß Sie beim Erzeugen einer REL-Datei den Wert 255 schreiben, weil dieser nämlich als Endmarkierung beim Lesen dient. Hierzu jedoch später mehr.
In den Zeile 60 und 70 lesen wir nun noch den Fehlerkanal aus und geben die " Record not present"- Fehlermeldung aus, um die blinkende Floppy-LED zu löschen und schließen anschließend die beiden offenen Files - schon haben wir eine REL-Datei zur Verfügung!

DER SCHREIBZUGRIFF                      

Möchten wir nun mit unserer selbst erstellten REL-Datei arbeiten, so müssen wir sie natürlich öffnen. Hierbei ist darauf zu achten, daß wir dieselbe Datensatzlänge angeben, wie wir sie beim Erzeugen der Datei verwendet haben. Andernfalls kommt die Floppy nämlich mit der Verwaltung der Datensätze durcheinander, was verheerende Folgen bei Schreibzugriffen haben kann. Benutzen Sie am Besten also den gleichen OPEN-Befehl, den Sie auch beim Erstellen benutzt haben! ! !
Wenn wir jetzt etwas in unsere Datei schreiben möchten, so verfahren wir im Prinzip genauso, wie beim Erstellen der Datei ( denn das war ja nichts anderes als das Schreiben in eine REL-Datei) .
Wir öffnen also zunächst Befehlskanal und REL-Datei, positionieren mittels Befehlskanal auf den gewünschten Datensatz und schreiben über die logische Filenummer der REL-Datei Daten in diesen Satz hinein. Hier ein Beispiel:

10 OPEN 1,8,15                          
20 OPEN 2,8,3,"TEST,R,"+CHR$(80)        
30 PRINT#1,"P"+CHR$(3)+CHR$(1)+CHR$(0)+ 
   CHR$(1)                              
40 PRINT#2,"DIESER TEXT WIRD NUN IN DA  
   TENSATZ NUMMER EINS GESPEICHERT!";   
50 CLOSE1: CLOSE2                       

Im Positionierbefehl wird wieder die Sekundäradresse 3 verwendet. Diesmal positionieren wir jedoch auf Byte 1 des ersten Datensatzes unserer Datei " TEST" ( Die Werte 1 und 0 entsprechen der LO/ HI-Darstellung der Zahl 1-->256*0+1=1) . In Zeile 40 wird dann mit einem ganz normalen PRINT#- Befehl ein Text in den positionierten Datensatz geschrieben. Da der Datensatz diesmal schon existiert brauchen wir demnach auch keinen Fehler von der Floppy auszulesen, da vorraussichtlich keiner auftritt.
Anstelle des Textes könnte natürlich auch eine Stringvariable stehen. Achten Sie bitte darauf, daß Sie nie längere Texte in einen Datensatz schreiben, als selbiger lang ist, da Sie sonst einen Teil der Daten im folgenden Datensatz verlieren könnten.
Wichtig ist auch, ob Sie beim Schreiben das Semikolon (" ;") verwenden, oder nicht. Verwenden Sie es nicht, so können Sie beim Lesen den INPUT#- Befehl verwenden. Dieser erkennt das Ende eines Lesevorgangs immer an einem " Carriage Return Code"( kurz " CR"= CHR$(13)), der von einem PRINT# OHNE Semikolon immer auto- matisch gesendet wird. In dem Fall müssen Sie aber auch bedenken, daß ein Text den Sie schreiben nie länger als die Datensatzlänge-1 sein darf, da das CR ebenfalls als ganzes Zeichen in den Datensatz geschrieben wird.
Nun ist, wie wir später sehen werden, das Lesen mittels INPUT# nicht immer von Vorteil, weshalb Sie einen Text auch MIT Semikolon schreiben können. In dem Fall müssen wir später beim Lesen eine GET#- Schleife verwenden, da keine Endmarkierung ( das " CR") für den INPUT#- Befehl geschrieben wurde.
DER LESEZUGIFF Auch der Lesezugriff weicht nicht sonderlich von den bisherigen Beispielen ab. Wie immer öffnen die beiden Floppykanäle und positionieren auf den gewünschten Datensatz. Nun haben wir zwei Möglichkeiten unsere Daten wieder auszulesen:
Wurden die Daten OHNE Semikolon geschrieben, so genügt ein einfaches " INPUT#2, A$" um unseren Text wieder zu Lesen und in A$ abzulegen.
Wurden Sie MIT Semikolon geschrieben, so müssen wir den umständlicheren Weg über eine GET#- Abfrage gehen. Dazu zwei Anmerkungen:
1) Bei der GET#- Abfrage sollten nicht mehr Zeichen gelesen werden, als maximal in dem Datensatz vorhanden sein können. Bei einer Länge von 80 Zeichen wird die GET#- Schleife also nicht mehr als 80 mal durchlaufen.
2) Was tun wir, wenn der Datensatzinhalt kürzer ist, als die festgelegte Datensatzlänge? Wie ich oben schon einmal erwähnte, dient der Byte-Wert 255 als Endmarkierung innerhalb einer REL-Datei. Dies stellt sich so dar, daß ein leerer Datensatz alle Bytes mit dem Wert 255 gefüllt hat. Schreiben wir nun einen Text in diesen Da- tensatz, so werden alle benötigten Zeichen mit dem Text überschieben.
Das darauf folgende Zeichen enthält dann aber immer noch den Wert 255 .
Dementsprechend können wir sagen, daß wenn wir beim Lesen eines Strings dieses Zeichen erhalten, der String zu Ende sein muß.
Durch diese beiden Punkte ergibt sich also folgende Schleife zum Lesen eines Strings:

 90 ...                                 
100 A$=""                               
110 FOR i=1 TO 80                       
120 GET#2,B$                            
130 IF ASC(B$)=255 THEN 160             
140 A$=A$+B$                            
150 NEXT                                
160 ...                                 
DATABANKING MIT RELATIVEN FILES         

Sie sehen, daß das Arbeiten mit REL-Files trotz aller Gegenteiligen Vorraussagen eigentlich relativ einfach ist.
Wir müssen jeweils nur richtig positionieren und können dann beliebig Lesen und Schreiben. Nun gibt es jedoch noch einige Kniffe, die man kennen sollte, wenn man effektiv mit relativen Dateien arbeiten möchte. Diese will ich nun ansprechen.
DATENFELDER:
Bei jeder Datenverarbeitung werden Sie meist mehrere Angaben in einem Datensatz machen. Einfachstes Beispiel ist hier eine Adressverwaltung. Hier müssen Sie pro Datensatz einen Namen, Strasse, Wohnort, Telefonnummer, etc. angeben, die Sie nachher auch immer wieder auf anhieb in Ihrer Adressdatei finden müssen. Diese einzelnen Einträge in einem Datensatz nennt man Datenfelder. Wie bei relativen Files so üblich, sollte man sich dann jeweils auf eine maximale Länge eines Datenfeldes beschränken. Sie könnten nun für jedes Datenfeld eine eigene REL-Datei anlegen, also beispielsweise eine Datei mit 30 Zeichen pro Satz für alle Namen, eine mit 40 Zeichen für alle Straßen, eine mit 15 Zeichen für alle Telefonnummern, eine mit 4 Zeichen für alle Postleitzahlen usw. Diese Lösung birgt jedoch ein größeres Problem in sich: der C64 verwaltet nämlich immer nur EINE offene REL-Datei.
Das bedeutet in der Praxis, daß Sie jedesmal, wenn Sie eine komplette Adresse ausgeben wollen, alle Ihre REL-Files nacheinander öffnen, lesen und schließen müssen. Was das an Programmierund Zeitaufwand beim Zugriff bedeutet ist verheerend. Deshalb geht man in der Regel einen anderen Weg. Halen wir doch einfach einmal an dem Beispiel der Adressverwaltung fest. Zunächst wollen wir uns einmal überlegen, welche und wieviele Felder wir verwenden wollen, und wie lang sie im einzelnen sein sollen. Für unsere kleine Adressverwaltung wollen wir 6 Felder pro Datensatz definieren:

1) "Name"         (20 Zeichen)          
2) "Vorname"      (15 Zeichen)          
3) "Straße"       (30 Zeichen)          
4) "Postleitzahl" ( 4 Zeichen)          
5) "Ort"          (30 Zeichen)          
6) "Telefon"      (15 Zeichen)          

Kommen wir nun zu dem Lösungsweg, denn man hier in der Regel geht. Anstelle von 6 einzelnen Dateien legen wir nun eine einzige Datei an, in der in einem Datensatz jeweils alle 6 Felder abgelegt werden. Dadurch ergibt sich eine Datensatzlänge von 114 Zeichen (20+15+30+4+30+15=114) . Wir können nun wiederum zwei Wege gehen, mit denen wir die sechs Felder in einem Datensatz speichern. Ich gehe dabei davon aus, daß die Einträge vom Programm schon abgefragt wurden und in Stringvariablen stehen:
Die einfachere, dafür jedoch unflexiblere, Methode sieht folgendermaßen aus:
Wir schreiben mit mehreren PRINT#- Befehlen OHNE Semikolon alle Stringvariablen hintereinander in ein Datenfeld hinein. Später können wir sie genauso wieder mittels INPUT# einlesen. Hierbei ist es egal, wie lang ein Feldeintrag ist, solange er die vorgegebene Länge nicht überschreitet ( wäre das bei allen Feldern nämlich der Fall, so würden wir mehr Zeichen in einen Datensatz schreiben, wie dieser lang ist, was man tunlichst unterlassen sollte) . Je nach dem, wie flexibel unser Adressverwaltungsprogramm sein soll entstehen nun jedoch diverse Schwierigkeiten. So müssen wir zum Beispiel immer alle Felder eines Datensatzes einlesen, wenn wir eine Datei z. B. nach einem einzelnen Feld sortieren möchten. Für gerade diese Aufgabe werden dann immer 5 Felder zuviel gelesen, was sich wiederum auf die Verarbeitungszeit ReLativ auswirkt. Das zweite Problem ist die Endmarkierung nach jedem Feldeintrag. Wie oben ja schon dargestellt müssen wir bei dieser Methode OHNE Semikolon arbeiten, und in dem Fall hängt PRINT# immer ein ' CR' an einen String an. Dadurch müssen wir von den obigen Feldlängen jeweils ein Zeichen abziehen ( der Name z. B. darf nicht mehr 20, sondern nur noch 19 Zeichen lang sein) .
Sie sehen also, daß diese Methode zwar einfacher zu programmieren, aber sicherlich unflexibler ist.
( bitte Teil 2 Laden. . . .)

Valid HTML 4.0 Transitional Valid CSS!