home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1989 / 06 / anwendg / dbdoc1.pas next >
Encoding:
Pascal/Delphi Source File  |  1989-01-24  |  16.2 KB  |  423 lines

  1. (* ------------------------------------------------------ *)
  2. (*                      DBDOC.PAS                         *)
  3. (* Demonstration des Zugriffs auf dBase III-Daten-        *)
  4. (* bankfiles aus Turbo Pascal. Das Programm gibt den      *)
  5. (* Inhalt einer dBase III-Datei auf dem Bildschirm aus.   *)
  6. (* Dabei wird insbesondere der Umgang mit den einzelnen   *)
  7. (* Unterprogrammen gezeigt.                               *)
  8. (*            (c) 1989  G.Born  & TOOLBOX                 *)
  9. (* ------------------------------------------------------ *)
  10. PROGRAM dbdoc;
  11.  
  12. (* definiere die Datentypen und die globalen Variablen    *)
  13. (* für den Zugriff auf die .DBF Datei                     *)
  14.  
  15. USES Crt, Dos;
  16.  
  17. CONST
  18.   PathLength  = 65;
  19.   Word_len    = 2;                    (* Länge Word       *)
  20.   Byte_len    = 1;                    (* Länge Byte       *)
  21.  
  22. TYPE
  23.   header = RECORD             (* Header einer dBase Datei *)
  24.              version   : BYTE;
  25.                               (* Version 03H oder 83H     *)
  26.              datum     : ARRAY [1..3] OF BYTE;
  27.                               (* Datum JJ MM TT           *)
  28.              records   : LONGINT;
  29.                               (* Records in Datenbank     *)
  30.              headerb   : word;
  31.                               (* Zahl der Bytes im Kopf   *)
  32.              recordb   : word;
  33.                               (* Zahl der Bytes pro Record*)
  34.              reserve   : ARRAY [1..20] OF BYTE;
  35.                               (* reservierte Bytes        *)
  36.            END;
  37.  
  38. TYPE
  39.   feld = RECORD               (* Feldbeschreibung im Kopf *)
  40.            fname       : ARRAY [1..11] OF BYTE;
  41.                               (* Feldname 11 Zeichen      *)
  42.            ftyp        : BYTE;
  43.                               (* C N L D M                *)
  44.            dummy1      : ARRAY [1..4] OF BYTE;
  45.                               (* Dummy Feld               *)
  46.            laenge      : BYTE;
  47.                               (* Zahl der Stellen         *)
  48.            komma       : BYTE;
  49.                               (* Zahl der Nachkommastellen*)
  50.            dummy2      : ARRAY [1..2] OF BYTE;
  51.                               (* reservierte Bytes        *)
  52.            id          : BYTE;
  53.                               (* ID Byte                  *)
  54.            dummy3      : ARRAY [1..11] OF BYTE;
  55.                               (* reserviert               *)
  56.          END;
  57.  
  58. TYPE
  59.   Name   = STRING[PathLength];   (* Typ Filename          *)
  60.   dbtyp  = FILE;                 (* Datenbankfile untyped *)
  61.   dbsatz = ARRAY [1..1024] OF BYTE;  (* Typ für Datensatz *)
  62.  
  63. VAR
  64.   kopf     : header;           (* Variable f. Dateiheader *)
  65.   felder   : ARRAY [0..128] OF feld;        (* 128 Felder *)
  66.   anzahl   : LONGINT;                  (* Zahl der Felder *)
  67.   FileName : Name;                     (* Dateiname       *)
  68.   DbFile   : dbtyp;                    (* File            *)
  69.  
  70.   Buffer   : dbsatz;
  71.   recnr    : LONGINT;                 (* Satznummer Dbase *)
  72.   jahr, monat, tag, wtag : word;      (* Datum            *)
  73.   i,j   : INTEGER;                    (* Index            *)
  74.   tmp   : CHAR;                       (* Hilfsvariable    *)
  75.  
  76. (* ------------------------------------------------------ *)
  77. (*                    Hilfsroutinen                       *)
  78.  
  79. PROCEDURE Write_hex (value, len : INTEGER);
  80.   {  Ausgabe eines Wertes als Hexzahl auf der Standard-    }
  81.   {  ausgabe. Durch Len wird festgelegt, ob ein            }
  82.   {  Byte (Len = 1) oder Wort (Len = 2) ausgegeben         }
  83.   {  werden soll.                                          }
  84.  
  85. CONST Hexzif : ARRAY [0..15] OF CHAR = '0123456789ABCDEF';
  86. VAR temp : INTEGER;
  87.  
  88. BEGIN
  89.   IF len = Word_len THEN BEGIN       (* 2 Bytes ?         *)
  90.     temp := Swap (value) AND $0FF;   (* high byte holen   *)
  91.     Write(Hexzif[temp DIV 16]:1, Hexzif[temp MOD 16]:1);
  92.   END;
  93.   temp := value AND $0FF;            (* low byte holen    *)
  94.   Write(Hexzif[temp DIV 16]:1, Hexzif[temp MOD 16]:1);
  95. END;  { Write_hex }
  96.  
  97. FUNCTION Open(VAR fp: dbtyp; fname: Name): BOOLEAN;
  98.   {  Öffne eine Datei und gebe Ergebnis als boolean zurück }
  99.  
  100. BEGIN
  101.   Assign(fp,fname);                  (* setze Filename    *)
  102. {$I-}                                (* Errorcheck off    *)
  103.   Reset(fp);                         (* open file         *)
  104. {$I+}                                (* Errorcheck on     *)
  105.   IF IOResult = 0 THEN
  106.     Open := TRUE
  107.   ELSE
  108.     Open := FALSE;
  109. END;  { Open }
  110.  
  111. PROCEDURE GetHeader (VAR handle : dbtyp);
  112.   { Die Routine liest den Dateiheader ein und prüft, ob es }
  113.   { sich um eine gültige DBASE III Datei handelt. Im Fehler}
  114.   { fall terminiert das Programm mit einer Meldung.        }
  115.  
  116. BEGIN
  117.   BlockRead(handle, kopf, 1);      (* lese Kopf der Datei *)
  118.   IF Eof(handle) THEN BEGIN        (* dBase Datei ?       *)
  119.     WriteLn('Keine dBase III-Datei, da (EOF) erreicht');
  120.     Halt;
  121.   END;
  122.   WITH kopf DO BEGIN
  123.     IF (version <> $83) AND (version <> $03) THEN BEGIN
  124.                                    (* kein dBase Header ? *)
  125.       WriteLn('Keine dBase III-Datei, da Header ',
  126.               '(Code) falsch');
  127.       Write('Code : ');
  128.       Write_hex(kopf.version, Byte_len); (* setze Code ab *)
  129.       Halt;
  130.     END ELSE
  131.       IF version = $02 THEN BEGIN  (* dBase II Header     *)
  132.         WriteLn ('dBase II Header');
  133.         Halt;
  134.        END;
  135.   END;
  136. END;  { GetHeader }
  137.  
  138. PROCEDURE GetFieldDef (VAR handle : dbtyp);
  139.   {  lese und decodiere die Feldbescheibung der dBase III- }
  140.   {  Datei, es sind maximal 128 Felder zulässig            }
  141.  
  142. VAR i, j    : INTEGER;
  143.     headend : BYTE;
  144.  
  145. BEGIN
  146.   anzahl := ((kopf.headerb - 1) DIV 32) - 1;
  147.                    (* Zahl der Felder                     *)
  148.                    (* Reset Datei um mit neuer Puffersize *)
  149.   Reset (handle,32);          (* zugreifen zu können      *)
  150.   Seek (handle, 1);           (* setze Zeiger auf 2. Feld *)
  151.   FOR i := 1 TO anzahl DO BEGIN
  152.                               (* lese n Felddefinitionen  *)
  153.     BlockRead (handle, felder[i], 1);
  154.     IF Eof(handle) THEN BEGIN        (* Fehler abfangen?  *)
  155.       WriteLn('Fehler: Ende Feldbeschreibung erreicht');
  156.       Halt;
  157.      END;
  158.   END;
  159.  
  160.   { prüfe ob nächstes Byte das Header Ende signalisiert    }
  161.  
  162.   Reset(handle, 1);             (* als File mit Bytes op  *}
  163.   seek(handle, kopf.headerb-1); (* auf Endezchn i. Kopf   *)
  164.   BlockRead(handle, headend,1); (* lese Endezeichen       *)
  165.   IF headend <> $0D THEN BEGIN  (* Ende = 0DH             *)
  166.     WriteLn('Fehler: Header Ende nicht gefunden');
  167.     Halt;
  168.   END;
  169.   recnr := kopf.headerb;        (* merke Feldanfang       *)
  170.   Reset(handle, 1);             (* Datei als Bytes öffnen *)
  171. END; { GetFieldDef }
  172.  
  173. PROCEDURE GetRecord (VAR handle: FILE; VAR satz : dbsatz);
  174.   {  lese einen Satz aus der DBASE III - Datenbank und     }
  175.   {  gebe das Ergebnis in satz zurück. Die Daten sind      }
  176.   {  als ASCII - Text in der Datenbank abgelegt.           }
  177.  
  178. BEGIN
  179.   Seek(handle,recnr);          (* positioniere Lesezeiger *)
  180.   BlockRead(handle, satz, kopf.recordb);
  181.                                (* lese Satz in Buffer     *)
  182.   IF Eof(handle) THEN BEGIN    (* EOF erreicht -> Fehler  *)
  183.     WriteLn('EOF erreicht !!!');
  184.     Halt;
  185.   END;
  186. END;  { GetRecord }
  187.  
  188. PROCEDURE PutRecord (VAR handle: FILE; VAR satz : dbsatz);
  189.   {  schreibe einen Satz in die DBASE III - Datenbank.     }
  190.   {  Die Daten sind als ASCII - Text im Puffer, geordnet   }
  191.   {  nach Feldern, abzulegen.                              }
  192.  
  193. BEGIN
  194.   Seek(handle,recnr);       (* positioniere Schreibzeiger *)
  195.   BlockWrite(handle, satz, kopf.recordb);
  196.                             (* in die Datenbank schreiben *)
  197.   GetDate(jahr, monat, tag, wtag);        (* lese Datum   *)
  198.  
  199.   kopf.datum[1] := jahr MOD 100;   (* Jahr 0 .. 99        *)
  200.   kopf.datum[2] := monat;          (* Monat               *)
  201.   kopf.datum[3] := tag;            (* Tag                 *)
  202.  
  203.   Seek(handle,1);                  (* auf Datumsfeld      *)
  204.   BlockWrite(handle,kopf.datum,3); (* Datum aktualisieren *)
  205. END; { PutRecord }
  206.  
  207. PROCEDURE AppendBlank (VAR handle : FILE);
  208.   { Hänge einen leeren Satz in die DBASE III - Datenbank an}
  209.   { nach dem Aufruf steht der Schreiblesezeiger auf diesem }
  210.   { Satz, d.h. PutRecord kann direkt Daten speichern.      }
  211.  
  212. VAR tmp : BYTE;
  213.     i   : INTEGER;
  214.  
  215. BEGIN
  216.   recnr := kopf.headerb + kopf.recordb * kopf.records;
  217.                                            (* calc record *)
  218.   Seek(handle, recnr);                     (* auf Ende    *)
  219.   FOR i := 1 TO kopf.recordb DO BEGIN
  220.     tmp := $20;               (* setz Blank in Puffer und *)
  221.     BlockWrite(handle,tmp,1); (* in Datei schreiben       *)
  222.   END;
  223.   tmp := $1A;                 (* EOF - Marke anhängen     *)
  224.   BlockWrite(handle,tmp,1);   (* schreibe Marke           *)
  225.   GetDate(jahr,monat,tag,wtag);    (* lese Datum          *)
  226.  
  227.   kopf.datum[1] := jahr MOD 100;   (* Jahr 0 .. 99        *)
  228.   kopf.datum[2] := monat;          (* Monat               *)
  229.   kopf.datum[3] := tag;            (* Tag                 *)
  230.   Seek (handle,1);                 (* auf Datumsfeld      *)
  231.   BlockWrite(handle,kopf.datum,3); (* Datum aktualisieren *)
  232.  
  233.   kopf.records := kopf.records + 1;(* Korrektur Recordzahl*)
  234.   Seek (handle, 4);              (* auf Position in Header*)
  235.  BlockWrite (handle,kopf.records,4);
  236.                                   (* Header aktualisieren *)
  237. END; { AppendBlank }
  238.  
  239. PROCEDURE Skip;
  240.   { Positioniere den Schreib-/Lesezeiger einen Satz weiter.}
  241.  
  242. BEGIN
  243.   recnr := recnr + kopf.recordb;  (* nächster Satz        *)
  244.  
  245. END; { Skip }
  246.  
  247. PROCEDURE GotoBottom;
  248.   { Positioniere den Schreib-/Lesezeiger auf Satz 1.       }
  249.  
  250. BEGIN
  251.   recnr := kopf.headerb;          (* erster Satz          *)
  252. END; { GotoBottom }
  253.  
  254. FUNCTION DBEof (VAR handle: FILE): BOOLEAN;
  255.   { Prüfe, ob EOF() der Datenbank erreicht ist             }
  256.  
  257. BEGIN                       (* Dateiende erreicht ?       *)
  258.   IF recnr >= kopf.headerb + kopf.recordb*kopf.records THEN
  259.     DBEof := TRUE                        (* ja            *)
  260.   ELSE
  261.     DBEof := FALSE;                      (* nein          *)
  262. END;  { DBEof }
  263.  
  264. (* ------------------------------------------------------ *)
  265. (*                   Hauptprogramm                        *)
  266.  
  267. BEGIN
  268.                                         (* Kopf ausgeben  *)
  269.   ClrScr;
  270.   WriteLn ('DBASE III (DBF) DOC             ',
  271.            ' (c) Born Version 1.0');
  272.   WriteLn;
  273.   Write ('File    : ');
  274.   Read (FileName);                      (* lese Dateiname *)
  275.   WriteLn;
  276.   IF Length(FileName) = 0 THEN BEGIN    (* Leereingabe ?  *)
  277.     WriteLn ('Der Name der Eingabedatei fehlt');
  278.     Halt;
  279.   END;
  280.  
  281.     {------------------------------------------------------}
  282.     {      *** Bearbeitung der DBASE III Datei ***         }
  283.     {  Dabei ist darauf zu achten, daß ein File mit dem    }
  284.     {  angegegeben Namen existiert.                        }
  285.     {------------------------------------------------------}
  286.  
  287.   IF NOT (Open (DbFile,FileName)) THEN BEGIN
  288.                                    (* Datei vorhanden?    *)
  289.     WriteLn ('Datei existiert nicht');
  290.     Halt;
  291.    END;
  292.  
  293.     {------------------------------------------------------}
  294.     { lese und decodiere den Header der dBase III-Datei    }
  295.     {------------------------------------------------------}
  296.  
  297.   GetHeader(DbFile);               (* lese Header         *)
  298.  
  299.     {------------------------------------------------------}
  300.     { ***  Ausgabe des Headers der dBase III-Datei ***     }
  301.     { Die Version gibt dabei an, ob intern Memofelder be-  }
  302.     { nutzt wurden (version = 83H -> Memodatei)            }
  303.     {------------------------------------------------------}
  304.   WITH kopf DO BEGIN
  305.     WriteLn ('Header der dBase III-Datei');
  306.     WriteLn;
  307.     Write ('Version      ');         (* Version DBF Datei *)
  308.     Write_hex (version,Byte_len);
  309.     WriteLn;
  310.     WriteLn ('Datum        ', datum[3],':',
  311.                               datum[2],':',datum[1]);
  312.     WriteLn ('Records      ', records);
  313.     WriteLn ('Header Länge ', headerb);
  314.     WriteLn ('Record Länge ', recordb);
  315.     WriteLn;
  316.   END;
  317.   WriteLn ('Weiter, bitte die <RET> Taste betätigen');
  318.   tmp := ReadKey;
  319.  
  320.     {------------------------------------------------------}
  321.     { lese und decodiere die Feldbescheibung der dBase III-}
  322.     { Datei, es sind maximal 128 Felder zulässig           }
  323.     {------------------------------------------------------}
  324.  
  325.   GetFieldDef(DbFile);           (* lese Feldbeschreibung *)
  326.   WriteLn('Feldbeschreibung der Datei ', FileName);
  327.   WriteLn;
  328.   WriteLn('Feldname   │   Typ    │ Stellen │ Kommastellen');
  329.   WriteLn('───────────┼──────────┼─────────┼─────────────');
  330.  
  331.   FOR i := 1 TO anzahl DO BEGIN  (* n Felddefinitionen    *)
  332.     FOR j:= 1 TO 11 DO
  333.       Write(Chr(felder[i].fname[j])); (* Name des Feldes  *)
  334.     Write('│');
  335.     CASE Chr(felder[i].ftyp) OF       (* gebe Feldtyp aus *)
  336.       'N': Write('Numerisch │');
  337.       'C': Write('Character │');
  338.       'L': Write('Logical   │');
  339.       'D': Write('Datum     │');
  340.       'M': Write('Memo      │');
  341.     END; { case }
  342.  
  343.     Write ('    ',felder[i].laenge:2);
  344.     Write ('   │   ',felder[i].komma:2);
  345.     WriteLn;
  346.   END;
  347.   WriteLn('───────────┴──────────┴─────────┴─────────────');
  348.  
  349.     {------------------------------------------------------}
  350.     { *** Hinweis: Die Recordlänge ist 1 Byte größer als   }
  351.     {              dies aus den Feldlängen ersichtlich ist,}
  352.     {              da im ersten Byte des Records die In-   }
  353.     {              formation für gelöschte Sätze steht (*).}
  354.     {------------------------------------------------------}
  355.  
  356.   WriteLn ('Recordlänge in Bytes      ',kopf.recordb);
  357.   WriteLn ;
  358.   WriteLn ('Weiter, bitte die <RET> Taste betätigen');
  359.   tmp := ReadKey;
  360.  
  361.     {------------------------------------------------------}
  362.     { lese und decodiere die Datensätze der dBase III-Datei}
  363.     {------------------------------------------------------}
  364.  
  365.   WriteLn ('Datensätze der dBase III-Datei ', FileName);
  366.   WriteLn;
  367.  
  368.     {------------------------------------------------------}
  369.     { Hier wird gezeigt, wie der Inhalt der Datei satzweise}
  370.     { per FOR Schleife gelesen werden kann.                }
  371.     {------------------------------------------------------}
  372.  
  373.   GotoBottom;                          (* auf 1. Satz     *)
  374.   FOR i := 1 TO kopf.records DO BEGIN  (* Alle Records    *)
  375.     GetRecord(DbFile,Buffer);          (* lese Satz       *)
  376.     FOR j:= 1 TO kopf.recordb DO
  377.       Write (Chr(Buffer[j]));        (* dokumentiere Satz *)
  378.     WriteLn;
  379.     Skip;                              (* nächster Satz   *)
  380.   END;
  381.  
  382.     {------------------------------------------------------}
  383.     { Der Inhalt des ersten Satzes wird verändert und in   }
  384.     { die Datenbank zurückgespeichert                      }
  385.     {------------------------------------------------------}
  386.  
  387.   Buffer[2] := Ord ('H');              (* ändere Feld 1   *}
  388.   Buffer[3] := Ord ('a');
  389.   Buffer[4] := Ord ('l');
  390.   Buffer[5] := Ord ('l');
  391.   Buffer[6] := Ord ('o');
  392.   GotoBottom;                          (* auf 1. Satz     *)
  393.   PutRecord (DbFile,Buffer);           (* speichere Satz  *)
  394.  
  395.     {------------------------------------------------------}
  396.     { Alternativ besteht die Möglichkeit, die Datei satz-  }
  397.     { weise zu lesen, bis EOF() erreicht ist. Hierfür dient}
  398.     { die Funktion DBEof().                                }
  399.     {------------------------------------------------------}
  400.  
  401.   WriteLn('Lese Datei nochmals');
  402.   GotoBottom;                          (* auf 1. Satz     *)
  403.   WHILE NOT DBEof (DbFile) DO BEGIN
  404.     GetRecord (DbFile, Buffer);        (* lese Satz       *)
  405.     Skip;                              (* nächster Satz   *)
  406.   END;
  407.   WriteLn('EOF Erreicht');
  408.  
  409.     {------------------------------------------------------}
  410.     { Es wird ein leerer Satz angefügt und mit dem Inhalt  }
  411.     { des letzten Satzes überschrieben                     }
  412.     {------------------------------------------------------}
  413.  
  414.   WriteLn('Leersatz anhängen');
  415.   AppendBlank(DbFile);            (* Leersatz anhängen    *)
  416.   PutRecord(DbFile,Buffer);       (* alten Satz speichern *)
  417.   Close(DbFile);
  418.   WriteLn('Ende DBDOC');
  419.  
  420. END.
  421. (* ------------------------------------------------------ *)
  422. (*                  Ende von DBDOC.PAS                    *)
  423.