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