Magic Disk 64

home to index to html: MD9206-KURSE-FLOPPY-KURS_1-A.html
  Floppy-Kurs: "Es rappelt in der Kiste"
                 (Teil 2)               
--------------------------------------- 
Hallo  zum  zweiten  Teil  des   Floppy-
Kurses.  In der vorletzten MD hatten ei-
niges über  den  Floppybefehlskanal  und
die  Programmierung  sequentieller Files
gelernt. In diesem Teil wollen  wir  uns
nunmehr  mit  der relativen Dateiverwal-
tung beschäftigen, die zwar  etwas  kom-
plizierter  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 hin-
ter  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 gere-
gelt. Sie arbeiten mit sogenannten  "Da-
tensätzen",  oder  engl.  "Records".  Im
Prinzip kann man eine relative Datei mit
einem  externen  Variablenfeld  verglei-
chen. 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. Den-
noch 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 schrei-
ben 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 "Schrei-
ben" unterschieden. Wir öffnen ein  sol-
ches  File  ganz  einfach  um der Floppy
anzuzeigen, daß wir es nun benutzen wol-
len. Ob wir nun lesen oder schreiben ist
ganz  egal.  Die  Floppy erkennt automa-
tisch, wenn  wir  etwas  schreiben  oder
lesen.  Das  heißt also, daß wir bei der
Benutzung eines  relativen  Files  immer
auch  den Floppybefehlskanal öffnen müs-
sen. Ö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ön-
nen. Bevor wir das tun, sollten wir  uns
überlegen,  wie lang ein Datensatz unse-
res 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  Fi-
les  immer  gleich  lang sein müssen, um
der Floppy das Auffinden eines Datensat-
zes  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 die-
sen  angehängt  folgt  die  Typenkennung
",L," sowie der  Länge  des  Datensatzes
in  diesem  File.  Hier ein kleiner Hin-
weis:  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  Num-
mern  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 ei-
gentlich ganz einfach: wir sprechen  le-
diglich  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  Bei-
spiel also alle 300. Das Generieren die-
ser Sätze kann jetzt einige Zeit in  An-
spruch  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 rela-
tiven Files.                            
Wenn die Floppy mit dem Anlegen der  re-
lativen  Datei  fertig  ist  blinkt  sie
übrigens sowieso, da wir durch  den  Zu-
griff 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 Low- und 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 Da-
tensä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 Positionie-
rungsbefehl an die  Floppy.  Wohlgemerkt
geschieht  dies  über  den Befehlskanal!
Aus dem Beispiel ist die Syntax des  Po-
sitionierungsbefehls ersichtlich. Begin-
nend mit dem Zeichen "P" (für  "positio-
nieren")  werden  in Reihenfolge die Se-
kundäradresse der REL-Datei auf die sich
die Positionierung  beziehen  soll,  die
Datensatznummer  in  Lo/Hi-Folge,  sowie
die Byteposition innerhalb des  entspre-
chenden  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  positio-
nierten  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 er-
stellten REL-Datei arbeiten,  so  müssen
wir  sie  natürlich  öffnen. Hierbei ist
darauf zu achten, daß wir  dieselbe  Da-
tensatzlänge  angeben,  wie wir sie beim
Erzeugen der Datei verwendet haben.  An-
dernfalls  kommt  die Floppy nämlich mit
der Verwaltung der Datensätze  durchein-
ander,   was   verheerende   Folgen  bei
Schreibzugriffen  haben  kann.  Benutzen
Sie  am  Besten  also den gleichen OPEN-
Befehl, den Sie auch beim Erstellen  be-
nutzt 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  Daten-
satz 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  geschrie-
ben. Da der Datensatz diesmal schon exi-
stiert 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 verwen-
den. Dieser erkennt das Ende eines Lese-
vorgangs 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üs-
sen 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 Da-
tensatz 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 Endmarkie-
rung (das "CR")  für  den  INPUT#-Befehl
geschrieben wurde.                      
DER LESEZUGIFF                          
Auch der Lesezugriff weicht  nicht  son-
derlich  von  den  bisherigen Beispielen
ab. Wie immer öffnen die beiden  Floppy-
kanäle   und   positionieren   auf   den
gewünschten  Datensatz.  Nun  haben  wir
zwei  Möglichkeiten  unsere Daten wieder
auszulesen:                             
Wurden  die  Daten  OHNE  Semikolon  ge-
schrieben,  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  An-
merkungen:                              
1) Bei  der  GET#-Abfrage  sollten nicht
   mehr Zeichen gelesen werden, als  ma-
   ximal in dem Datensatz vorhanden sein
   können.  Bei  einer Länge von 80 Zei-
   chen  wird  die  GET#-Schleife   also
   nicht mehr als 80 mal durchlaufen.   
2) Was tun wir, wenn der Datensatzinhalt
   kürzer  ist,  als die festgelegte Da-
   tensatzlänge? Wie ich oben schon ein-
   mal 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. Schrei-
   ben  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 Vorraus-
sagen  eigentlich  relativ  einfach ist.
Wir müssen jeweils nur richtig  positio-
nieren  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 an-
sprechen.                               
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üs-
sen.  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än-
ge eines  Datenfeldes  beschränken.  Sie
könnten  nun  für  jedes  Datenfeld eine
eigene  REL-Datei  anlegen,  also   bei-
spielsweise  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 je-
desmal, wenn Sie eine komplette  Adresse
ausgeben  wollen,  alle  Ihre  REL-Files
nacheinander öffnen, lesen und schließen
müssen.  Was  das  an  Programmier-  und
Zeitaufwand  beim  Zugriff  bedeutet ist
verheerend.  Deshalb geht man in der Re-
gel  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  sol-
len.  Für unsere kleine Adressverwaltung
wollen wir 6 Felder pro Datensatz  defi-
nieren:                                 
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 Daten-
satz jeweils alle 6 Felder abgelegt wer-
den.  Dadurch  ergibt  sich  eine Daten-
satzlänge von 114  Zeichen  (20+15+30+4+
30+15=114). Wir können nun wiederum zwei
Wege gehen, mit denen wir die sechs Fel-
der 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 unflexible-
re, Methode  sieht  folgendermaßen  aus:
Wir   schreiben   mit  mehreren  PRINT#-
Befehlen  OHNE Semikolon alle  Stringva-
riablen  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  schrei-
ben,  wie  dieser lang ist, was man tun-
lichst unterlassen sollte). Je nach dem,
wie flexibel unser Adressverwaltungspro-
gramm  sein  soll  entstehen  nun jedoch
diverse Schwierigkeiten. So  müssen  wir
zum  Beispiel  immer  alle  Felder eines
Datensatzes einlesen, wenn wir eine  Da-
tei  z.B. nach einem einzelnen Feld sor-
tieren möchten. Für gerade diese Aufgabe
werden dann immer 5 Felder zuviel  gele-
sen, was sich wiederum auf die Verarbei-
tungszeit ReLativ auswirkt.  Das  zweite
Problem ist die Endmarkierung nach jedem
Feldeintrag.  Wie  oben  ja schon darge-
stellt 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 sicher-
lich unflexibler ist.                   
(bitte Teil 2 Laden....)                
Valid HTML 4.0 Transitional Valid CSS!