Datei

Transcription

Datei
1
9
Dateiverarbeitung
 2006 Pearson Education, Inc. All rights reserved.
2
9.1
9.2
9.3
9.4
9.5
9.6
9.7
9.8
9.9
9.10
9.11
Einführung
Die Datenhierarchie
Daten und Ströme
Erzeugung einer sequenziellen Datei
Daten von einer sequenziellen Datei lesen
Eine sequenzielle Datei aktualisieren
Dateien mit wahlfreiem Zugriff
Erzeugung einer Datei mit wahlfreiem Zugriff
Daten wahlfrei in eine Datei mit wahlfreiem Zugriff
schreiben
Sequenzielles Lesen aus einer Datei mit wahlfreiem
Zugriff
Fallstudie: Verarbeitung von Transaktionen
 2006 Pearson Education, Inc. All rights reserved.
3
9.1 Einführung
• Dateien
– Werden verwendet, um Daten dauerhaft (‘persistent’) zu
machen
• Permanente Speicherung von großen Datenmengen
– Speicherung auf sekundären Speichereinheiten
• Magnetplatten
• Halbleiterspeicher (Flash-Speicher)
• Optische Speichermedien
• Magnetbänder
 2006 Pearson Education, Inc. All rights reserved.
4
9.2 Die Datenhierarchie
• Bit
– Darstellung von einem von zwei Zuständen, 0 oder 1
– Kleinste unterstützte Dateneinheit
• Direkt in Hardwareschaltungen abgebildet
• Zeichen
– Ziffern, Buchstaben und spezielle Symbole
• Aus Bits zusammengesetzt
– Zeichensatz: Menge aller Zeichen, die auf einer
bestimmten Plattform verwendet werden
– chars werden in Bytes gespeichert (8 Bits)
– wchar_ts werden in mindestens zwei Bytes gespeichert
 2006 Pearson Education, Inc. All rights reserved.
5
9.2 Die Datenhierarchie
• Feld
– Aus Zeichen zusammengesetzt
– Hat eine bestimmte Bedeutung
– Beispiel
• Groß- und Kleinbuchstaben können einen Namen darstellen
• Datensatz (Record)
– Aus mehreren Feldern zusammengesetzt
– Wird in C als Struktur dargestellt
– Beispiel
• Datensatz für einen Angestellten könnte Personalnummer,
Name, Adresse usw. enthalten
– Ein Datensatz-Schlüssel ist ein Feld, das für alle Datensätze
eindeutig ist.
 2006 Pearson Education, Inc. All rights reserved.
6
9.2 Die Datenhierarchie
• Datei
– Aus einer Gruppe zusammengehöriger Datensätze
zusammengesetzt
– Beispiel:
• Gehaltsdatei, die einen Datensatz für jeden Angestellten enthält
– Unterschiedliche Varianten der Organisation von Datensätzen
in einer Datei
• Beispiel: Sequenzielle Datei
– Datensätze werden nach einem Schlüssel sortiert nacheinander
gespeichert
• Datenbank
– Aus einer Gruppe zusammengehöriger Dateien zusammengesetzt
– Verwaltet durch eine Gruppe von Programmen, die zusammen
Datenbank Management System (DBMS) genannt werden
 2006 Pearson Education, Inc. All rights reserved.
7
Fig. 9.1 Datenhierarchie.
 2006 Pearson Education, Inc. All rights reserved.
8
9.3 Dateien und Ströme
• Datei
– C betrachtet jede Datei als eine Folge von Bytes (Fig. 9.2).
– Jede Datei endet entweder mit einem ‘end-of-file marker’
oder an einer speziellen Byte-Nummer, die in einer
systeminternen, administrativen Datenstruktur steht.
– Wenn eine Datei geöffnet wird, wird ein Strom (‘stream’)
mit ihr verbunden.
– Drei Dateien und die mit ihnen assoziierten Ströme werden
automatisch geöffnet, wenn die Programmausführung
beginnt: standard input, standard output und standard error.
– Ströme stellen Kommunikationskanäle zwischen Dateien
und Programmen zur Verfügung.
 2006 Pearson Education, Inc. All rights reserved.
9
Fig. 9.2 | C-Sicht einer Datei mit n Bytes.
 2006 Pearson Education, Inc. All rights reserved.
10
9.3 Dateien und Ströme
• Der Standardeingabestrom ermöglicht es einem
Programm Daten von der Tastatur zu lesen und der
Standardausgabestrom ermöglicht es einem Programm
Daten auf den Bildschirm zu schreiben.
• Das Öffnen einer Datei gibt einen Zeiger auf eine FILE
Struktur (definiert in <stdio.h>) zurück, die
Informationen zur Bearbeitung der Datei enthält.
• standard input, standard output und standard error werden
über die Dateizeiger stdin, stdout und stderr
angesprochen.
 2006 Pearson Education, Inc. All rights reserved.
11
9.3 Dateien und Ströme
• Die Standardbibliothek stellt viele Funktionen für das
Lesen aus Dateien und das Schreiben in Dateien zur
Verfügung.
• Die Funktion fgetc liest ein einzelnes Zeichen aus einer
Datei. Sie erwartet einen FILE Zeiger für die Datei, aus
der das Zeichen gelesen werden soll, als Argument.
• Der Aufruf fgetc( stdin ) liest ein Zeichen von stdin
(der Standardeingabe).
Dies ist äquivalent mit dem Aufruf getchar().
 2006 Pearson Education, Inc. All rights reserved.
12
9.3 Dateien und Ströme
• Die Funktion fputc schreibt ein einzelnes Zeichen in eine
Datei. Sie erwartet das zu schreibende Zeichen und einen
FILE Zeiger für die Datei, in die das Zeichen geschrieben
werden soll, als Argument.
• Der Aufruf fputc( 'a', stdout ) schreibt das Zeichen
'a' nach stdout (der Standardeingabe).
Dies ist äquivalent mit dem Aufruf putchar( 'a' ).
 2006 Pearson Education, Inc. All rights reserved.
13
9.3 Dateien und Ströme
• Viele andere Funktionen, die Daten von Ein- und Ausgabe
lesen bzw. schreiben, haben gleichartig benannte Dateiverarbeitungsfunktionen.
• So können beispielsweise die Funktionen fgets und
fputs benutzt werden, um eine Zeile aus einer Datei zu
lesen bzw. eine Zeile in eine Datei zu schreiben.
• In den nächsten Abschnitten werden die dateiverarbeitenden Äquivalente der Funktionen scanf und printf
verwendet: fscanf und fprintf.
 2006 Pearson Education, Inc. All rights reserved.
14
9.4 Erzeugung einer sequenziellen Datei
• Dateistruktur
– Die Strukturierung von Dateien ist Aufgabe des
Programmierers
• C selbst strukturiert eine Datei in keiner Weise, sondern
arbeitet mit einer reinen Folge von Bytes.
 2006 Pearson Education, Inc. All rights reserved.
15
9.4 Erzeugung einer sequenziellen Datei
• Öffnen einer Datei zur Ausgabe
– Ein C Programm verwaltet jede Datei mit einer separaten
FILE Struktur (deklariert in stdio.h).
– Hierzu wird einer Variablen vom Typ FILE* durch die
Funktion fopen ein Zeiger auf die FILE Struktur der zu
öffnenden Datei zugewiesen.
– fopen übernimmt zwei Argumente: Einen Dateinamen
(einschließlich Pfadinformation zum Ort der Datei im
Dateiverzeichnis) und einen Dateiöffnungs-Modus.
– Der Dateiöffnungs-Modus "w" zeigt an, dass die Datei zum
Schreiben geöffnet wird.
– Falls die Datei nicht existiert und zum Schreiben geöffnet
wird, erzeugt fopen die Datei.
 2006 Pearson Education, Inc. All rights reserved.
16
Häufiger Programmierfehler
Öffnet man eine existierende Datei zur
Ausgabe (Dateiöffnungs-Modus "w"),
wird der vorhandene Inhalt der Datei
ohne Warnung verworfen.
 2006 Pearson Education, Inc. All rights reserved.
17
Modus
Beschreibung
r
w
Öffnet eine vorhandene Datei zur Eingabe.
Erzeugt eine Datei zur Ausgabe. Falls die Datei schon existiert, wird
der vorhandene Inhalt verworfen.
a
Öffnet oder erzeugt eine Datei für die Ausgabe ans Ende der Datei.
r+
w+
Öffnet eine vorhandene Datei zur Aktualisierung (Ein- und Ausgabe).
Erzeugt eine Datei zur Aktualisierung. Falls die Datei schon existiert,
wird der vorhandene Inhalt verworfen.
Öffnet oder erzeugt eine Datei zur Aktualisierung. Geschrieben wird
am Ende der Datei.
a+
rb, wb, ab,
rb+, wb+, ab+
Gleiche Funktionsweise wie oben beschrieben, jedoch nicht im Text-,
sondern im Binärmodus.
Fig. 9.5 | Dateiöffnungsarten.
 2006 Pearson Education, Inc. All rights reserved.
18
9.4 Erzeugung einer sequenziellen Datei
• Verwendung des FILE-Zeigers
– In die Datei schreiben
• Z.B. formatiertes Schreiben unter Verwendung der Funktion
fprintf , die den FILE-Zeiger als erstes Argument übernimmt.
– Datei schließen
• Funktion fclose
• Übernimmt den FILE-Zeiger als einziges Argument
• Gibt die Datei wieder frei
 2006 Pearson Education, Inc. All rights reserved.
19
Tipp zur Performanz
Wenn ein Programm eine Datei nicht länger
benötigt, sollte sie durch einen Aufruf von
fclose explizit freigegeben werden.
 2006 Pearson Education, Inc. All rights reserved.
20
9.4 Erzeugung einer sequenziellen Datei
• Test auf Dateiende mit feof
– Die Funktion feof testet, ob der end-of-file Indikator für
die Datei, deren FILE-Zeiger sie übernimmt, gesetzt ist.
– Der end-of-file Indikator informiert das Programm, dass
keine Daten mehr zu verarbeiten sind.
– Auch stdin kann auf end-of-file getestet werden;
das ‘Dateiende’ wird dann durch eine spezielle Tastenkombination simuliert.
– Fig. 9.6 zeigt die Tastenkombinationen um end-of-file
einzulesen für verschiedene Betriebssysteme.
 2006 Pearson Education, Inc. All rights reserved.
21
Plattform
Tastenkombination
UNIX/Linux/Mac OS X
<Strg-d> (in einer eigenen Zeile)
Microsoft Windows
<Strg-z> (manchmal mit zusätzlichem Enter)
VMS
<Strg-z>
Fig. 9.6 | Simulation der EOF-Markierung durch Tastatureingaben.
 2006 Pearson Education, Inc. All rights reserved.
22
9.4 Erzeugung einer sequenziellen Datei
• Formatiertes Schreiben mit fprintf
– Zum formatierten Schreiben in eine Datei wird die
Funktion fprintf verwendet.
– fprintf ist äquivalent mit printf, bis auf die Tatsache,
dass fprintf einen Zeiger auf die zu schreibende Datei
als erstes Argument übernimmt.
– Bei Erfolg gibt fprintf (wie auch printf) die Gesamtzahl der erfolgreich geschriebenen Zeichen zurück.
– Im Fehlerfall wird der Fehlerindikator für den Dateistrom gesetzt und eine negative Zahl zurückgegeben.
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.4: fig09_04.c
2
// Creating a sequential file.
3
#include <stdio.h>
4
#include <stdlib.h> // exit
5
#define NAME_SIZE 30
Outline
6
7
int main( void )
8
{
fig09_04.c
(1 von 2)
9
unsigned int account;
10
char name[ NAME_SIZE ];
11
12
double balance;
13
FILE* cfPtr = fopen( "clients.txt", "w" );
14
if( cfPtr == NULL ) {
Öffnen der Datei clients.txt zur Ausgabe
fopen gibt NULL zurück, falls die Datei
nicht erfolgreich geöffnet wurde
15
fputs( "File could not be opened", stderr );
16
exit( 1 ); // exit program if unable to create file
17
23
} // end if
18
19
puts( "Enter the account, name, and balance." );
20
printf( "%s", "Enter EOF to end input.\n? " );
21
scanf( "%d%29s%lf", &account, name, &balance );
22
feof gibt 1 zurück, wenn der Nutzer EOF eingibt
23
// write account, name and balance into file with fprintf
24
while( ! feof( stdin ) ) {
25
fprintf( cfPtr, "%d %s %.2f\n", account, name, balance );
26
printf( "%s", "? " );
27
scanf( "%d%29s%lf", &account, name, &balance );
28
} // end while
29
30
Formatierte Ausgabe in
clients.txt mit fprintf
fclose schließt die Datei
fclose( cfPtr ); // closes file
31 } // end main
 2006 Pearson Education,
Inc. All rights reserved.
Enter
Enter
? 100
? 200
? 300
? 400
? 500
? ^Z
the account, name, and balance.
EOF to end input.
Jones 24.98
Doe 345.67
White 0.00
Stone -42.16
Rich 224.62
Outline
24
fig09_04.c
(2 von 2)
 2006 Pearson Education,
Inc. All rights reserved.
9.5 Daten von einer sequenziellen Datei
lesen
25
• Öffnen einer Datei zum Einlesen
– Hierzu wird einer Variablen vom Typ FILE* durch die
Funktion fopen ein Zeiger auf die FILE Struktur der zu
öffnenden Datei zugewiesen.
– fopen übernimmt zwei Argumente: Einen Dateinamen
(einschließlich Pfadinformation zum Ort der Datei im
Dateiverzeichnis) und einen Dateiöffnungs-Modus.
– Der Dateiöffnungs-Modus "r" zeigt an, dass die Datei zum
Lesen geöffnet wird.
– Falls die Datei nicht existiert und zum Lesen geöffnet
werden soll, gibt fopen den Wert NULL zurück.
 2006 Pearson Education, Inc. All rights reserved.
9.5 Daten von einer sequenziellen Datei
lesen
26
• Formatiertes Einlesen mit fscanf
– Zum formatierten Einlesen aus einer Datei wird die
Funktion fscanf verwendet.
– fscanf ist äquivalent mit scanf, bis auf die Tatsache,
dass fscanf einen Zeiger auf die einzulesende Datei als
erstes Argument übernimmt.
– Bei Erfolg gibt fscanf (wie auch scanf) die Anzahl der
erfolgreich gelesenen Argumente zurück. Dies kann der
Anzahl der erwarteten Werte entsprechen oder kleiner
sein aufgrund eines Lesefehlers oder des Erreichens von
end-of-file (EOF).
– Im Fehlerfall wird der passende Indikator (Fehler oder
EOF) für den Dateistrom gesetzt und - falls dies vor dem
erfolgreichen Einlesen von Daten passiert - EOF zurückgegeben.
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.7: fig09_07.c
2
// Reading and printing a sequential file.
3
#include <stdio.h>
4
#include <stdlib.h> // exit function prototype
5
#define NAME_SIZE 30
Outline
6
7
int main( void )
8
{
fig09_07.c
(1 von 2)
9
unsigned int account;
10
char name[ NAME_SIZE ];
11
12
double balance;
13
FILE* cfPtr = fopen( "clients.txt", "r" );
Öffnen von clients.txt zum Einlesen
14
15
if( cfPtr == NULL ) {
fopen gibt NULL zurück, falls clients.txt
nicht erfolgreich geöffnet werden konnte
16
fputs( "File could not be opened", stderr );
17
exit( 1 ); // exit program if file could not be opened
18
27
} // end if
19
20
printf( "%-10s%-13s%s\n", "Account", "Name", "Balance" );
21
22
// display each record in file
23
24
while( fscanf( cfPtr, "%d%29s%lf", &account, name, &balance ) == 3 )
printf( "%-10d%-13s%7.2f\n", account, name, balance );
25
26
fclose( cfPtr );
27 } // end main
fscanf gibt die Anzahl der erfolgreich eingelesenen Argumente
zurück; wenn das Ende der Datei clients.txt erreicht wird,
ist dieser Wert ungleich 3 und die Schleife wird beendet.
 2006 Pearson Education,
Inc. All rights reserved.
Account
100
200
300
400
500
Name
Jones
Doe
White
Stone
Rich
Balance
24.98
345.67
0.00
-42.16
224.62
Outline
28
fig09_07.c
(2 von 2)
 2006 Pearson Education,
Inc. All rights reserved.
9.5 Daten von einer sequenziellen Datei
lesen
29
• Datei-Positionszeiger
– Byte-Nummer des nächsten Byte zum Lesen oder Schreiben
• Keine Variable eines Zeigertyps, sondern ein int-Wert
– Die Anweisung
rewind( cfPtr );
setzt den Datei-Positionszeiger an den Anfang (d.h. Byte 0)
der Datei, der cfPtr zugeordnet ist.
 2006 Pearson Education, Inc. All rights reserved.
9.5 Daten von einer sequenziellen Datei
lesen
30
Kreditabfrage Programm
• Das folgende Programm erlaubt es, Listen von
– Kunden mit Kontostand Null,
– Kunden mit Kreditstand (d.h. Kunden, denen das
Unternehmen Geld schuldet) und
– Kunden mit Debitstand (d.h. Kunden, die dem Unternehmen
Geld für Waren und Dienstleistungen schulden)
auszugeben.
• Ein Kreditstand ist ein negativer Wert; ein Debitstand ist
ein positiver Wert.
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.8: fig09_08.c
2
// Credit inquiry program.
3
#include <stdio.h>
4
#include <stdlib.h> // exit function prototype
5
#define NAME_SIZE 30
6
7
enum RequestType { ZERO_BALANCE = 1, CREDIT_BALANCE, DEBIT_BALANCE, END };
8
9
int main( void )
Outline
31
fig09_08.c
(1 von 3)
10 {
11
unsigned int request;
12
unsigned int account;
13
char name[ NAME_SIZE ];
14
double balance;
15
16
FILE* cfPtr = fopen( "clients.txt", "r" );
17
18
if( cfPtr == NULL ) {
19
fputs( "File could not be opened", stderr );
20
exit( 1 ); // exit program if file could not be opened
21
} // end if
22
23
24
// display request options
printf( "%s", "\nEnter request\n"
25
" 1 - List accounts with zero balances\n"
26
" 2 - List accounts with credit balances\n"
27
" 3 - List accounts with debit balances\n"
28
" 4 - End of run\n? " );
29
scanf( "%u", &request );
30
 2006 Pearson Education,
Inc. All rights reserved.
31
// process user's request
32
while( request != END ) {
33
switch( request ) {
34
case ZERO_BALANCE:
35
puts( "\nAccounts with zero balances:" );
36
// read and display file contents (until eof)
37
while( fscanf( cfPtr, "%d%29s%lf", &account, name, &balance ) == 3 )
38
if( balance == 0 )
39
40
41
printf( "%-10d%-13s%7.2f\n", account, name, balance );
43
// read and display file contents (until eof)
44
while( fscanf( cfPtr, "%d%29s%lf", &account, name, &balance ) == 3 )
45
if( balance < 0 )
46
printf( "%-10d%-13s%7.2f\n", account, name, balance );
break;
case DEBIT_BALANCE:
49
puts( "\nAccounts with debit balances:" );
50
// read and display file contents (until eof)
51
while( fscanf( cfPtr, "%d%29s%lf", &account, name, &balance ) == 3 )
52
53
54
(2 von 3)
case CREDIT_BALANCE:
puts( "\nAccounts with credit balances:" );
48
fig09_08.c
break;
42
47
Outline
32
if( balance > 0 )
printf( "%-10d%-13s%7.2f\n", account, name, balance );
break;
55
} // end switch
56
rewind( cfPtr ); // return cfPtr to beginning of file
57
printf( "%s", "\n? " );
58
scanf( "%u", &request );
59
} // end while
60
puts( "End of run." );
61
fclose( cfPtr ); // close file
62 } // end main
 2006 Pearson Education,
Inc. All rights reserved.
Outline
Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4 - End of run
? 1
fig09_08.c
Accounts with zero balances:
400
Metzger
0.00
(3 von 3)
33
? 2
Accounts with credit balances:
300
Muller
-112.00
? 3
Accounts with debit balances:
100
Becker
99.90
200
Schneider
199.90
500
Schmidt
22.20
? 4
End of run.
 2006 Pearson Education,
Inc. All rights reserved.
34
9.6 Eine sequenzielle Datei aktualisieren
• Aktualisierung eines Datensatzes in einer
sequenziellen Datei
– Der neue Datensatz könnte länger als der alte sein.
• Falls dies so ist, werden Teile des nächsten sequenziellen
Datensatzes überschrieben.
• Um dies zu vermeiden, müssen alle Datensätze hinter dem
neuen Datensatz kopiert werden.
• Für große Dateien kann der entsprechende Aufwand
unakzeptabel werden.
 2006 Pearson Education, Inc. All rights reserved.
35
9.7 Dateien mit wahlfreiem Zugriff
• Dateien mit wahlfreiem Zugriff
– Notwendig für Anwendungen mit direktem Zugriff
• Beispielsweise Systeme zur Transaktionsverarbeitung
– Ein Datensatz kann eingefügt, gelöscht oder modifiziert
werden, ohne andere Datensätze zu beeinflussen.
– Verschiedene Techniken können eingesetzt werden.
• Voraussetzung ist, dass alle Datensätze die gleiche Länge haben
und in der Reihenfolge ihrer Schlüssel angeordnet sind.
– Das Programm kann den genauen Ort jedes Datensatzes
berechnen.
• Basis hierfür sind Größe und Schlüssel des Datensatzes.
 2006 Pearson Education, Inc. All rights reserved.
36
Fig. 9.9 | C-Sicht einer Datei mit wahlfreiem Zugriff.
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
37
• Die Funktion fwrite schreibt eine bestimmte Anzahl
von Bytes, beginnend an einer bestimmten
Speicheradresse, unformatiert in eine Datei.
• Die Daten werden in der Datei ab der Stelle geschrieben,
auf die der Dateipositions-Zeiger gerade zeigt.
• Entsprechend liest die Funktion fread eine bestimmte
Anzahl von Bytes ab der Stelle in der Datei, auf die der
Dateipositions-Zeiger gerade zeigt, in einen
Speicherbereich beginnend an einer angegebenen
Speicheradresse.
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
38
•Funktion fwrite
– Schreibt eine Anzahl von Bytes aus einem Speicherbereich
in eine Datei an die Stelle, auf die der Positionszeiger zeigt.
– Parameter:
• Ein const void*, der auf das Anfangsbyte eines Arrays im
Speicher zeigt
• Ein size_t, der die Anzahl der Bytes angibt, die für ein
Element des Arrays geschrieben werden sollen
• Ein size_t, der die Anzahl der Elemente im Array angibt,
die geschrieben werden sollen
• Zeiger auf eine FILE-Struktur, die die Ausgabedatei angibt
– Beispiel:
fwrite( &number, sizeof( int ), 1, fPtr );
 2006 Pearson Education, Inc. All rights reserved.
39
Portabilitäts-Tipp
Die Verwendung von fwrite ist systemabhängig
und kann dazu führen, dass sich Programme auf
verschiedenen Plattformen unterschiedlich
verhalten.
Die Daten werden nicht formatiert (wie im Fall
von fprintf ), sondern in Form von ‘rohen
Daten’ (also als Bytes) geschrieben.
 2006 Pearson Education, Inc. All rights reserved.
40
Portabilitäts-Tipp
Ein Programm, das unformatierte Daten liest (die
mit fwrite geschrieben wurden), muss auf einem
System kompiliert und ausgeführt werden, das mit
dem Programm kompatibel ist, das die Daten
geschrieben hat.
Unterschiedliche Systeme können unterschiedliche
interne Datendarstellungen verwenden
(Beispiel: Big Endian – Little Endian).
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
41
• Headerdateien
– Separate Dateien, die nur Typdefinitionen,
Funktionsprototypen und Konstanten enthalten
• Erlauben dem Compiler nutzerdefinierte Typen und Funktionen
zu erkennen, wenn sie anderswo eingesetzt werden
– Haben im allgemeinen .h Erweiterung für Dateinamen
• Testanwendungsdateien (Driver files)
– Programme zum Testen von Typen und Funktionen
– Enthalten eine main Funktion und sind ausführbar
– Haben im allgemeinen .c Erweiterung für Dateinamen
•.h und .c Dateien werden als Quelldateien
(source code files) bezeichnet .
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
42
• #include Präprozessor-Direktive
– Wird benutzt, um Headerdateien einzufügen
• Weist den C Präprozessor an, die Direktive durch eine Kopie
des Inhalts der angegebenen Datei zu ersetzen
– Anführungszeichen kennzeichnen eine nutzerdefinierte
Headerdatei
• Der Präprozessor sucht zuerst im aktuellen Verzeichnis
– Falls die Datei nicht gefunden wird, sucht er im C
Standard-include-Verzeichnis
– Winkelklammern kennzeichnen die C Standardbibliothek
• Präprozessor sucht nur im C Standard-include-Verzeichnis
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
43
• Präprozessordirektiven zur Vermeidung des
mehrfachen Einbindens von Headerdateien
– Verhindern, dass Code mehr als einmal eingebunden wird
• #ifndef – “if not defined”
– Überspringe diesen Code, falls schon definiert, d.h. eingebunden
• #define
– Definiere einen Namen zur Vermeidung des nochmaligen Einbindens
• #endif
– Falls der Header schon zuvor eingebunden wurde
• Name ist schon definiert und Headerdatei wird nicht mehr eingebunden
– Verhindert Fehlermeldungen durch Mehrfachdefinitionen
– Beispiel:
#ifndef CLIENTDATA_H
#define CLIENTDATA_H
… // code
#endif
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
44
• Aufgabenstellung:
– Es soll ein Kreditverarbeitungs-Programm geschrieben
werden, das bis zu 100 Datensätze fester Länge in einer
Datei speichern kann. Jeder Datensatz soll aus einer
Kontonummer (die auch als Schlüssel für den Datensatz
dient), Nachname, Vorname und Kontostand bestehen.
– Das Programm soll
• ein bestehendes Konto aktualisieren können,
• einen Datensatz für ein neues Konto einfügen können,
• ein Konto löschen und
• die Datensätze aller vorhandenen Konten als formatierte
Textdatei abspeichern oder auf die Konsole ausgeben können.
– Es soll eine Datei mit wahlfreiem Zugriff verwendet
werden.
 2006 Pearson Education, Inc. All rights reserved.
9.8 Erzeugung einer Datei mit
wahlfreiem Zugriff
45
– Das Kreditverarbeitungs-Programm wird in mehreren
Schritten / Teilprogrammen entwickelt.
– Das erste Teilprogramm dient nur dazu, die
Grundstruktur der verwendeten Datei zu erzeugen,
indem 100 leere Datensätze erzeugt und in eine Datei
mit wahlfreiem Zugriff geschrieben werden.
– Die Datensätze werden als Variablen vom Typ einer
struct Clientdata erzeugt.
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.11: ClientData.h
2
// Type ClientData definition used in Fig. 9.12 – Fig. 9.15.
3
#ifndef CLIENTDATA_H
4
#define CLIENTDATA_H
5
6
typedef struct {
7
unsigned int accountNumber;
8
char lastName[ 16 ];
9
char firstName[ 12 ];
10
double balance;
Headerdatei, die die Definition des
Typs ClientData enthält.
Outline
46
ClientData.h
(1 von 1)
11 } ClientData; // end definition of type ClientData
12
13 #endif
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 9.12: fig09_12.c
2
// Creating a random-access file sequentially.
3
#include <stdio.h>
4
#include <stdlib.h> // exit
5
Outline
Einfügen der Headerdatei, die die Definition
des Typs ClientData enthält.
#include "ClientData.h" // Definition of type ClientData
fig09_12.c
8
int main( void )
(1 von 1)
9
{
6
47
7
10
size_t i; // loop counter
11
ClientData blankClient = { 0, "", "", 0.0 }; // default record
12
13
FILE* cfPtr = fopen( "credit.dat", "wb" );
credit.dat im Binärmodus öffnen
14
15
if( cfPtr == NULL ) {
16
fputs( "File could not be opened.", stderr );
17
exit( 1 ); // exit program if unable to open file
18
} // end if
19
20
// output 100 blank records to file
21
for( i = 0; i < 100; ++i )
22
fwrite( &blankClient, sizeof( ClientData ), 1, cfPtr );
23
24
fclose( cfPtr );
25
fputs( "File written." );
26 } // end main
Daten in blankClient als Bytes
in credit.dat abspeichern
 2006 Pearson Education,
Inc. All rights reserved.
9.9 Daten wahlfrei in eine Datei mit
wahlfreiem Zugriff schreiben
48
• Daten an bestimmte Position schreiben
– Für Ein- und Ausgabe im Binärmodus öffnen
• Verwenden der Dateiöffnungsart "rb+"
– Einsatz der Funktion fseek, um den Positionszeiger an die
gewünschte Position zu setzen
• Beispiel:
( n – 1 ) * sizeof( ClientData )
• Byteposition für nten ClientData Datensatz
– Verwendung von fwrite, um Daten zu schreiben
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.13: fig09_13.c
2
// Writing data randomly to a random-access file.
3
#include <stdio.h>
4
#include <stdlib.h> // exit
Outline
49
5
6
#include "ClientData.h" // ClientData type definition
fig09_13.c
8
int main( void )
9
{
(1 von 3)
7
10
ClientData client = { 0, "", "", 0.0 }; // default record
11
12
FILE* cfPtr = fopen( "credit.dat", "rb+" );
13
14
if( cfPtr == NULL ) {
15
fputs( "File could not be opened.", stderr );
16
exit( 1 ); // exit program if unable to open file
17
Verwenden von rb+, um
credit.dat zur Ein- und
Ausgabe im Binärmodus zu öffnen
} // end if
18
19
// require user to specify account number
20
printf( "%s", "Enter account number (1 to 100, 0 to end input)\n? " );
21
scanf( "%d", &client.accountNumber );
 2006 Pearson Education,
Inc. All rights reserved.
22
23
// user enters information, which is copied into file
24
while( client.accountNumber > 0 && client.accountNumber <= 100 ) {
25
// user enters last name, first name and balance
26
printf( "%s", "Enter lastname, firstname, balance\n? " );
27
28
// set record lastName, firstName and balance values
29
fscanf( stdin, "%14s%9s%lf", client.lastName,
30
fig09_13.c
(2 von 3)
client.firstName, &client.balance );
31
32
// seek position in file of user-specified record
33
fseek( cfPtr, ( client.accountNumber - 1 ) *
34
Outline
50
Positionszeiger wird auf
gewünschte Byteposition gesetzt
sizeof( ClientData ), SEEK_SET );
35
36
// write user-specified information in file
37
fwrite( &client, sizeof( ClientData ), 1, cfPtr );
38
39
// enable user to enter another account
40
printf( "%s", "Enter account number\n? " );
41
scanf( "%d", &client.accountNumber );
42
} // end while
Der ClientData Datensatz wird an
die gewünschte Position geschrieben
43
44
fclose( cfPtr );
45 } // end main
 2006 Pearson Education,
Inc. All rights reserved.
Enter account number (1 to
? 37
Enter lastname, firstname,
? Barker Doug 0.00
Enter account number
? 29
Enter lastname, firstname,
? Brown Nancy -24.54
Enter account number
? 96
Enter lastname, firstname,
? Stone Sam 34.98
Enter account number
? 88
Enter lastname, firstname,
? Smith Dave 258.34
Enter account number
? 33
Enter lastname, firstname,
? Dunn Stacey 314.33
Enter account number
? 0
100, 0 to end input)
balance
balance
Outline
51
fig09_13.c
(3 von 3)
balance
balance
balance
 2006 Pearson Education,
Inc. All rights reserved.
9.9 Daten wahlfrei in eine Datei mit
wahlfreiem Zugriff schreiben
52
• Daten an bestimmte Position schreiben
– Der Funktionsprototyp für fseek ist
int fseek( FILE* stream, long int offset,
int whence );
– Hierbei ist offset die Anzahl der Bytes für das Setzen des
Positionszeigers gerechnet ab whence in der Datei, auf die
stream zeigt - ein positiver offset sucht vorwärts und
ein negativer sucht in Rückwärtsrichtung.
– Das Argument whence ist einer der Werte SEEK_SET,
SEEK_CUR oder SEEK_END (alle definiert in <stdio.h>),
die den Ort angeben, an dem die Suche beginnt.
 2006 Pearson Education, Inc. All rights reserved.
9.9 Daten wahlfrei in eine Datei mit
wahlfreiem Zugriff schreiben
53
• Daten an bestimmte Position schreiben
– Die symbolische Konstante SEEK_SET gibt an, dass der
Positionszeiger relativ zum Anfang der Datei um die
Größe des Offset erhöht wird.
– SEEK_CUR gibt an, dass die Suche an der aktuellen
Position des Positionszeigers in der Datei beginnt und
SEEK_END gibt an, dass die Suche am Ende der Datei
beginnt.
 2006 Pearson Education, Inc. All rights reserved.
9.9 Daten wahlfrei in eine Datei mit
wahlfreiem Zugriff schreiben
54
• Um die Programme dieses Kapitels übersichtlich zu
halten, wird nicht auf mögliche Fehlerfälle getestet.
• Professionelle Programme sollten jedoch testen, ob
Funktionen wie fscanf , fseek und fwrite korrekt
arbeiten, indem ihre Rückgabewerte überprüft werden.
• fscanf gibt die Anzahl der erfolgreich gelesenen
Datenwerte zurück oder den Wert EOF falls beim
Einlesen der Daten ein Problem auftritt.
• fseek gibt einen Wert ungleich Null zurück, falls die
Suchoperation nicht durchgeführt werden kann.
• fwrite gibt die Anzahl der erfolgreich ausgegebenen
Werte zurück . Falls diese Zahl kleiner als das dritte
Argument des Funktionaufrufs ist, trat ein Fehler auf.
 2006 Pearson Education, Inc. All rights reserved.
9.10 Sequenzielles Lesen aus einer
Datei mit wahlfreiem Zugriff
55
• Funktion fread
– Liest eine Anzahl von Bytes aus dem Eingabestrom (der mit
der aktuellen Dateiposition verknüpft ist) in ein Objekt im
Speicher
– Parameter:
• Ein const void*, der auf das Anfangsbyte eines Arrays im
Speicher zeigt
• Ein size_t, der die Anzahl der Bytes angibt, die in ein Element
des Arrays eingelesen werden sollen
• Ein size_t, der die Anzahl der Elemente des Arrays angibt, die
eingelesen werden sollen
• Zeiger auf eine FILE-Struktur, die die Eingabedatei angibt
– Beispiel:
fread( &client, sizeof( ClientData ), 1, cfPtr );
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.14: fig09_14.c
2
// Reading a random-access file sequentially.
3
#include <stdio.h>
4
#include <stdlib.h> // exit
Outline
56
5
6
#include "ClientData.h" // ClientData type definition
fig09_14.c
8
int main( void )
9
{
(1 von 2)
7
10
ClientData client = { 0, "", "", 0.0 }; // default record
11
12
FILE* cfPtr = fopen( "credit.dat", "rb" );
13
14
if( cfPtr == NULL ) {
15
fputs( "File could not be opened.", stderr );
16
exit( 1 ); // exit program if unable to open file
17
} // end if
18
19
printf( "%-10s%-16s%-11s%10s\n", "Account", "Last Name",
20
"First Name", "Balance" );
21
Daten aus credit.dat als Bytes in client abspeichern
22
// read all records from file
23
while( fread( &client, sizeof( ClientData ), 1, cfPtr ) == 1 ) {
24
// display record
25
if( client.accountNumber != 0 )
26
printf( "%-10d%-16s%-11s%10.2f\n", client.accountNumber,
27
client.lastName, client.firstName, client.balance );
28
} // end while
29
30
fclose( cfPtr );
31 } // end main
 2006 Pearson Education,
Inc. All rights reserved.
Account
Last Name
First Name
29
33
37
88
96
Brown
Dunn
Barker
Smith
Stone
Nancy
Stacey
Doug
Dave
Sam
Balance
-24.54
314.33
0.00
258.34
34.98
Outline
57
fig09_14.c
(2 von 2)
 2006 Pearson Education,
Inc. All rights reserved.
9.11 Fallstudie: Verarbeitung von
Transaktionen
58
• Ausführliches Beispiel:
Durchführung verschiedener Transaktionen von
Kontendaten
– Sequenzielles Lesen aus einer Binärdatei mit wahlfreiem
Zugriff und Schreiben der gelesenen Informationen in eine
Textdatei oder auf die Konsole
– Aktualisieren eines zuvor in die Binärdatei geschriebenen
Datensatzes
– Schreiben eines neuen Datensatzes in die Binärdatei
– Löschen eines vorhandenen Datensatzes aus der Binärdatei
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 9.15: fig09_15.c
2
// Bank-account program reads a random-access file sequentially,
3
// updates data previously written to the file, creates data to
4
// be placed in the file, and deletes data previously in the file.
5
#include <stdio.h>
6
#include <stdlib.h> // exit
fig09_15.c
#include "ClientData.h" // ClientData type definition
(1 von 9)
7
8
9
Outline
59
10 // prototypes
11 unsigned int enterChoice( void );
12 void createTextFileOrPrint( FILE* readPtr );
13 void updateRecord( FILE* fPtr );
14 void newRecord( FILE* fPtr );
15 void deleteRecord( FILE* fPtr );
16
17 enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END };
18
19 int main( void )
20 {
21
unsigned int choice; // user's choice
22
FILE* cfPtr = fopen( "credit.dat", "rb+" );
23
24
if( cfPtr == NULL ) {
25
fputs( "File could not be opened.", stderr );
26
exit( 1 ); // exit program if unable to open file
27
} // end if
28
 2006 Pearson Education,
Inc. All rights reserved.
29
// enable user to specify action
30
while( ( choice = enterChoice() ) != END ) {
31
32
switch( choice ) {
case PRINT: // create text file from record file or print to console
33
createTextFileOrPrint( cfPtr );
34
break;
35
case UPDATE: // update record
36
updateRecord( cfPtr );
37
break;
38
case NEW: // create record
39
newRecord( cfPtr );
40
break;
41
deleteRecord( cfPtr );
43
break;
puts( "Incorrect choice\n" );
46
break;
48
(2 von 9)
default: // display message if user does not select valid choice
45
47
fig09_15.c
case DELETE: // delete existing record
42
44
Outline
60
} // end switch
} // end while
49
50
fclose( cfPtr );
51 } // end main
52
 2006 Pearson Education,
Inc. All rights reserved.
53 // enable user to input menu choice
54 unsigned int enterChoice( void )
55 {
56
unsigned int menuChoice;
57
// display available options
58
printf( "%s", "\nEnter your choice\n"
59
"1 - store text file or print to console\n"
60
"2 - update an account\n"
61
"3 - add a new account\n"
62
"4 - delete an account\n"
63
"5 - end program\n? " );
Outline
61
fig09_15.c
(3 von 9)
64
65
scanf( "%u", &menuChoice ); // receive choice from user
66
return menuChoice;
67 } // end function enterChoice
68
 2006 Pearson Education,
Inc. All rights reserved.
69 // create text file or print to console
70 void createTextFileOrPrint( FILE* readPtr )
71 {
72
ClientData client = { 0, "", "", 0.0 }; // default
73
74
unsigned int writeChoice;
75
// display available options
76
printf( "%s", "\nEnter your choice\n"
77
"1 - store a formatted text file of acounts"
78
79
80
FILE*-Zeiger als Parameter
Outline
für das
Einlesen von Daten aus credit.dat
record
fig09_15.c
(4 von 9)
" called \"accounts.txt\"\n"
"2 – write to console\n? " );
scanf( "%u", &writeChoice ); // receive choice from user
81
82
62
FILE* writePtr = ( writeChoice == 1 ?
83
fopen( "accounts.txt", "w" ) : stdout );
Verwendung von writeChoice,
um writePtr mit Ausgabedatei
oder stdout zu verknüpfen
84
85
// exit program if file cannot be opened
86
if( writePtr == NULL ) {
87
fputs( "File could not be opened.", stderr );
88
exit( 1 ); // exit program if unable to open file
89
} // end if
90
 2006 Pearson Education,
Inc. All rights reserved.
91
92
fprintf( writePtr, "%-10s%-16s%-11s%10s\n", "Account",
93
"Last Name", "First Name", "Balance" );
94
95
rewind( readPtr ); // set file-position pointer to beginning of file
96
97
// copy all records from record file into text file
98
while( fread( &client, sizeof( ClientData ), 1, readPtr ) == 1 ) {
99
100
// write single record to text file
(5 von 9)
if( client.accountNumber != 0 ) // skip empty records
101
fprintf( writePtr, "%-10d%-16s%-11s%10.2f\n", client.accountNumber,
102
103
Outline
Verwendung
von rewind,
um sicherzustellen, dass
der Positionszeiger am
Anfang
der Datei ist
fig09_15.c
63
client.lastName, client.firstName, client.balance );
} // end while
104
105
if( writeChoice == 1 ) { // output file was written
106
printf( "File %s written.\n", "'accounts.txt'" );
107
fclose( writePtr );
108
} //
109 } // end function createTextFile
110
 2006 Pearson Education,
Inc. All rights reserved.
111 // update balance in record
Outline
112 void updateRecord( FILE* fPtr )
113 {
114
unsigned int account; // account number
115
double transaction; // transaction amount
116
ClientData client = { 0, "", "", 0.0 }; // default record
fig09_15.c
118
printf( "%s", "Enter account to update ( 1 - 100 ): " );
119
scanf( "%d", &account );
(6 von 9)
120
// move file-position pointer to correct record in file
121
fseek( fPtr, ( account - 1 ) * sizeof( ClientData ), SEEK_SET );
117
64
122
123
// read record from file
124
fread( &client, sizeof( ClientData ), 1, fPtr );
125
126
127
128
Feststellen, ob der Datensatz
Informationen enthält
if( client.accountNumber != 0 ) { // update record
printf( "%-10d%-16s%-11s%10.2f\n\n", client.accountNumber,
client.lastName, client.firstName, client.balance );
129
// request transaction amount from user
130
printf( "%s", "\nEnter charge ( + ) or payment ( - ): " );
131
scanf( "%lf", &transaction );
132
client.balance += transaction; // update record balance
133
134
printf( "%-10d%-16s%-11s%10.2f\n\n", client.accountNumber,
client.lastName, client.firstName, client.balance );
135
// move file-position pointer to correct record in file
136
fseek( fPtr, ( account - 1 ) * sizeof( ClientData ), SEEK_SET );
137
// write updated record over old record in file
138
fwrite( &client, sizeof( ClientData ), 1, fPtr );
139
} // end if
140
else // display message if account does not exist
141
Daten aus dem Objekt client mit
fwrite in die Binärdatei schreiben
printf( "Account #%d has no information\n", account );
142 } // end function updateRecord
 2006 Pearson Education,
Inc. All rights reserved.
143
Outline
144 // create and insert record
145 void newRecord( FILE* fPtr )
65
146 {
147
unsigned int account; // account number
148
ClientData client = { 0, "", "", 0.0 }; // default record
fig09_15.c
150
printf( "%s", "Enter new account number ( 1 - 100 ): " );
151
scanf( "%d", &account );
(7 von 9)
152
// move file-position pointer to correct record in file
153
154
fseek( fPtr, ( account - 1 ) * sizeof( ClientData ), SEEK_SET );
155
// read record from file
156
fread( &client, sizeof( ClientData ), 1, fPtr );
149
157
158
Feststellen, ob der Datensatz
keine Informationen enthält
if( client.accountNumber == 0 ) { // create record
159
// user enters last name, first name and balance
160
printf( "%s", "Enter lastName, firstName, balance\n? " );
161
scanf( "%14s%9s%lf", client.lastName, client.firstName, &client.balance );
162
163
client.accountNumber = account;
164
165
// move file-position pointer to correct record in file
166
fseek( fPtr, ( account - 1 ) * sizeof( ClientData ), SEEK_SET );
167
// insert record in file
168
fwrite( &client, sizeof( ClientData ), 1, fPtr );
169
} // end if
170
else // display message if account does not exist
Daten aus dem Objekt client mit
fwrite in die Binärdatei schreiben
171
printf( "Account #%d already contains information\n", account );
172 } // end function newRecord
 2006 Pearson Education,
Inc. All rights reserved.
173
Outline
174 // delete an existing record
175 void deleteRecord( FILE* fPtr )
66
176{
177
unsigned int account; // account number
178
ClientData client; // stores record read from file
179
ClientData blankClient = { 0, "", "", 0.0 }; // blank client
180
181
printf( "%s", "Enter account number to delete ( 1 - 100 ): " );
182
scanf( "%d", &account );
183
184
// move file-position pointer to correct record in file
fseek( fPtr, ( account - 1 ) * sizeof( ClientData ), SEEK_SET );
fig09_15.c
(8 von 9)
185
186
// read record from file
187
fread( &client, sizeof( ClientData ), 1, fPtr );
188
189
Feststellen, ob der Datensatz
Informationen enthält
if( client.accountNumber != 0 ) { // delete record
190
// move file-position pointer to correct record in file
191
fseek( fPtr, ( account - 1 ) * sizeof( ClientData ), SEEK_SET );
192
// replace existing record with blank record
193
fwrite( &blankClient, sizeof( ClientData ), 1, fPtr );
194
printf( "Account #%d deleted.\n", account );
195
} // end if
196
else // display message if account does not exist
197
printf( "Account #%d does not exist.\n", account );
Leeren Datensatz in die
Datei kopieren, um Konto
wieder auf Null zu setzen
198 } // end function deleteRecord
 2006 Pearson Education,
Inc. All rights reserved.
Enter your choice
1 - store text file or print to console
2 - update an account
3 - add a new account
4 - delete an account
5 - end program
? 1
Enter your choice
1 - store a formatted text file of acounts called "accounts.txt"
2 - write to console
? 2
Account
Last Name
First Name
Balance
29
Brown
Nancy
-24.54
33
Dunn
Stacey
314.33
37
Barker
Doug
0.00
88
Smith
Dave
258.34
96
Stone
Sam
34.98
Outline
67
fig09_15.c
(9 von 9)
Enter your choice
1 - store text file or print to console
2 - update an account
3 - add a new account
4 - delete an account
5 - end program
? 1
Enter your choice
1 - store a formatted text file of acounts called "accounts.txt"
2 - write to console
? 1
File 'accounts.txt' written.
 2006 Pearson Education,
Inc. All rights reserved.

Documents pareils