Datei Ein

Transcrição

Datei Ein
Programmieren in C
Die C-Standardbibliothek: Datei Ein- und Ausgabe
Prof. Dr. Nikolaus Wulff
Das Dateisystem
• In C erfolgt die gesamte Ein- und Ausgabe durch
Lesen oder Schreiben von Strömen (stream).
• Periphere Geräten werden immer mit der selben
einheitlichen Schnittstelle angesprochen.
• Konsole stdout und die Tastatur stdin werden in C
als Dateien modelliert, die beim Programmstart
bereits geöffnet worden sind.
• Beim Programmstart kann diese Vorbelegung
übersteuert werden:
progamm.exe < eingabe.txt > ausgabe.txt
Prof. Dr. Nikolaus Wulff
2
FILE und <stdio.h>
• FILE ist als Struktur in <stdio.h> deklariert:
#ifndef _FILE_DEFINED
struct _iobuf {
int
_cnt; /* Anzahl Zeichen
char *_ptr; /* Zeiger auf Zeichen
int
_flag; /* Art des Dateizugriff
char *_base; /* Zeiger auf Puffer
int
_file; /* File Deskriptor
...
};
*/
*/
*/
*/
*/
typedef struct _iobuf FILE;
#define _FILE_DEFINED
extern FILE _iob[];
#define stdin (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
Prof. Dr. Nikolaus Wulff
3
Datei Funktions Makros
• Viele häufig benötigte Funktion zur Ein- und
Ausgabe entpuppen sich als einfache Makros:
#define getc(_stream)
(--(_stream)->_cnt >= 0 \
? 0xff & *(_stream)->_ptr++ : _filbuf(_stream))
#define putc(_c,_stream) (--(_stream)->_cnt >= 0 \
? 0xff & (*(_stream)->_ptr++ = \
(char)(_c)) : _flsbuf((_c),(_stream)))
#define getchar()
#define putchar(_c)
getc(stdin)
putc((_c),stdout)
• Wie die Deklarationen exakt aussehen hängt vom
verwendeten Compiler und Betriebssystem ab.
• Daumenregel: interne Bezeichner mit _XXX nicht
verwenden, diese sind meist nicht portabel.
Prof. Dr. Nikolaus Wulff
4
Datei Funktionen
Wichtige IO-Funktionen sind:
• fclose, fopen
Stream schließen oder öffnen
• feof
Testet ob Stream zu Ende ist
• ferror
Testet Stream auf Fehler
• fflush
Leert Puffer eines Streams
• fgetc, fputc
Liest/schreibt ein Zeichen
• fgets, fputs
Liest/schreibt eine Zeichenkette
• fscanf, fprintf
Liest/schreibt formatierte Daten
• fread, fwrite
Unformatiertes Lesen/Schreiben
• printf/scanf sind nur Spezialfälle von fprintf/fscanf.
Prof. Dr. Nikolaus Wulff
5
Datei Zeichenweise einlesen
int c;
FILE *stream = fopen("test.txt","r");
while(!feof(stream)) {
c = fgetc(stream);
printf("%c",c);
}
fclose(stream);
• Das obige Codefragment liest eine Datei test.txt.
• Die Datei wird mit dem read-only Parameter “r“ im
Lesemodus geöffnet. Schreiben ist “w“...
• Am Ende wird die Datei wieder geschlossen, d.h.
die Resourcen werden an das Betriebssystem
zurückgegeben.
Prof. Dr. Nikolaus Wulff
6
Datei Zeilenweise einlesen
#define MAX_LEN 256
void readfile() {
char* line = malloc(sizeof(char)*MAX_LEN);
FILE *stream = fopen("test.txt","rt");
while(!feof(stream)) {
fgets(line, MAX_LEN, stream);
printf("%s",line);
}
}
fclose(stream);
free(line);
• fgets liest Textdateien zeilenweise ein.
• Der notwendige Puffer, in dem die Zeile von fgets
kopiert wird, wurde zuvor mit malloc bereitgestellt.
• “rt“ read text weist das Öffnen einer Textdatei an.
Prof. Dr. Nikolaus Wulff
7
Formatierte Datei einlesen
void readfile() {
float x;
int
i;
char string[] = "interner Puffer gross genug";
FILE *stream = fopen("test.txt","r");
while(!feof(stream)) {
fscanf(stream, "%d %s %f",&i, string, &x);
}
}
printf("%s %d %f \n",string, i, x);
fclose(stream);
• Dateien mit fester Formatierung lassen sich mit
fscanf einlesen.
• fscanf benötigt die Adressen der zu lesenden
Variablen, deshalb &x und &i!
Prof. Dr. Nikolaus Wulff
8
Zeichenkette schreiben
FILE *stream;
char *string = "Hallo World";
stream = fopen("stext.txt","wt");
fputs(string,stream);
fclose(stream);
• fputs ist das Gegenstück zu fgets
• fputs schreibt eine Zeichenkette in eine Textdatei.
Prof. Dr. Nikolaus Wulff
9
Formatiertes Schreiben
FILE *stream;
int i = 2;
float x = 3.14;
char* s = "hallo";
stream = fopen("stext.txt","wt");
fprintf(stream,"%d %s %f",i,s,x);
fclose(stream);
• fprinft schreibt in Textdateien.
• Alle Formatanweisungen von printf gelten analog.
Prof. Dr. Nikolaus Wulff
10
Unformatiertes Schreiben
typedef struct {
char name[40];
char surname[40];
int age;
} Person;
void writePersons(FILE *stream, int len,
Person persons[]) {
/** write array size
*/
fwrite(&len,sizeof(int),1,stream);
/** write array at once */
fwrite(persons,sizeof(Person),len,stream);
}
• fwrite schreibt unformatierte Daten. Stream im
Modus “wb“ für write binary öffnen.
• Bei Arrays erst die Feldlänge len ausgeben, dann
geht später das Lesen einfacher...
Prof. Dr. Nikolaus Wulff
11
Unformatiertes Lesen
Person* readPersons(FILE *stream, int *len) {
Person *persons;
/** read array size
*/
fread(len,sizeof(int),1,stream);
/** allocate array
*/
persons = malloc(*len*sizeof(Person));
assert(persons != NULL);
•
•
•
•
}
/** read array at once */
fread(persons,sizeof(Person),*len,stream);
return persons;
fread ist das Gegenstück zu fwrite.
Zum Lesen wird zunächst die Feldlänge eingelesen
Dann Speicher alloziert und die Daten gelesen.
Achtung: len wurde als Zeiger übergeben...
Prof. Dr. Nikolaus Wulff
12
Weitere IO-Funktionen
Neben printf / scanf und fprintf / fscanf gibt es
Methoden, die direkt Speicheradressen verwenden:
• sscanf
• sprintf
Liest formatiert von einer Zeichenkette
Schreibt formatiert eine Zeichenkette
Zusätzlich gibt es noch analoge Schreibmethoden
für variable Argumentlisten aus <stdarg.h>:
• vprintf, vsprintf, vfprintf
Prof. Dr. Nikolaus Wulff
13
Komfortable Debug Messages
#define MAXSTRING 512
int debugEnabled = 1;
FILE *out = stdout;
void debug(char* file, int line, const char* fmt, ...) {
int len;
va_list args;
char message[MAXSTRING];
char *msg = message;
}
if (debugEnabled) {
sprintf(msg,"DEBUG %s [%d]: ",file, line);
len = strlen(message);
msg += len;
va_start(args, fmt);
vsnprintf(msg, MAXSTRING - len, fmt, args);
va_end(args);
fprintf (out,"%s",message);
}
• Kombinierte Anwendung von sprintf und vsnprintf,
um formatierte Debug Nachrichten variabler Länge
auszugeben.
Prof. Dr. Nikolaus Wulff
14
Zusammenfassung
• In <stdio.h> sind viele „stream“-basierte IO
Funktionen definiert, die ein einheitliches
Schreiben und Lesen ermöglichen.
• Hierbei ist es dann unerheblich ob dies die Tastatur,
die Shell, eine Datei oder Speicheradresse ist.
• Auf den ersten Blick verwirrend, aber eigentlich
genial. Es handelt sich um „Quellen“ und „Senken“,
die durch „Ströme“ verbunden sind...
• Die Beschäftigung mit dem Prinzip und der Logik
dieser Methoden ist sicherlich lohnend, da sie in
jeder Programmiersprache immer wieder
vorkommen.
Prof. Dr. Nikolaus Wulff
15