Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
Vorwort des Gutachters
1 Einstieg in C
2 Das erste Programm
3 Grundlagen
4 Formatierte Ein-/Ausgabe mit »scanf()« und »printf()«
5 Basisdatentypen
6 Operatoren
7 Typumwandlung
8 Kontrollstrukturen
9 Funktionen
10 Präprozessor-Direktiven
11 Arrays
12 Zeiger (Pointer)
13 Kommandozeilenargumente
14 Dynamische Speicherverwaltung
15 Strukturen
16 Ein-/Ausgabe-Funktionen
17 Attribute von Dateien und das Arbeiten mit Verzeichnissen (nicht ANSI C)
18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
19 Zeitroutinen
20 Weitere Headerdateien und ihre Funktionen (ANSI C)
21 Dynamische Datenstrukturen
22 Algorithmen
23 CGI mit C
24 MySQL und C
25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
26 Paralleles Rechnen
27 Sicheres Programmieren
28 Wie geht’s jetzt weiter?
A Operatoren
B Die C-Standard-Bibliothek
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch
Buch: C von A bis Z

C von A bis Z
3., aktualisierte und erweiterte Auflage, geb., mit CD und Referenzkarte
1.190 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1411-7
Pfeil 16 Ein-/Ausgabe-Funktionen
Pfeil 16.1 Was ist eine Datei?
Pfeil 16.2 Formatierte und unformatierte Ein-/Ausgabe
Pfeil 16.3 Standard-Streams
Pfeil 16.4 Höhere Ein-/Ausgabe-Funktionen
Pfeil 16.5 Datei (Stream) öffnen – »fopen«
Pfeil 16.5.1 Modus für »fopen()«
Pfeil 16.5.2 Maximale Anzahl geöffneter Dateien – »FOPEN_MAX«
Pfeil 16.6 Zeichenweise lesen und schreiben – »getchar()« und »putchar()«
Pfeil 16.6.1 Ein etwas portableres »getch()«
Pfeil 16.7 Zeichenweise lesen und schreiben – »putc()«/»fputc()« und »getc()«/»fgetc()«
Pfeil 16.8 Datei (Stream) schließen – »fclose()«
Pfeil 16.9 Formatiertes Einlesen/Ausgeben von Streams mit »fprintf()« und »fscanf()«
Pfeil 16.10 Standard-Streams in C
Pfeil 16.10.1 Standard-Streams umleiten
Pfeil 16.11 Fehlerbehandlung von Streams – »feof()«, »ferror()« und »clearerr()«
Pfeil 16.12 Gelesenes Zeichen in die Eingabe zurückschieben – »ungetc()«
Pfeil 16.13 (Tastatur-)Puffer leeren – »fflush()«
Pfeil 16.14 Stream positionieren – »fseek()«, »rewind()« und »ftell()«
Pfeil 16.15 Stream positionieren – »fsetpos()«, »fgetpos()«
Pfeil 16.16 Zeilenweise Ein-/Ausgabe von Streams
Pfeil 16.16.1 Zeilenweise lesen mit »gets()«/»fgets()«
Pfeil 16.16.2 Zeilenweise schreiben mit »puts()«/»fputs()«
Pfeil 16.16.3 Zeilenweise vom Stream einlesen mit »getline()« (nicht ANSI C)
Pfeil 16.16.4 Rezepte für zeilenweises Einlesen und Ausgeben
Pfeil 16.17 Blockweise lesen und schreiben – »fread()« und »fwrite()«
Pfeil 16.17.1 Blockweise lesen – »fread()«
Pfeil 16.17.2 Blockweise schreiben – »fwrite()«
Pfeil 16.17.3 Big Endian und Little Endian
Pfeil 16.18 Datei (Stream) erneut öffnen – »freopen()«
Pfeil 16.19 Datei löschen oder umbenennen – »remove()« und »rename()«
Pfeil 16.19.1 remove()
Pfeil 16.19.2 rename()
Pfeil 16.20 Pufferung einstellen – »setbuf()« und »setvbuf()«
Pfeil 16.20.1 Die Funktion »setbuf()«
Pfeil 16.20.2 Die Funktion »setvbuf()«
Pfeil 16.21 Temporäre Dateien erzeugen – »tmpfile()« und »tmpnam()«
Pfeil 16.21.1 »mkstemp()« – sichere Alternative für Linux/UNIX (nicht ANSI C)
Pfeil 16.22 Fehlerbehandlung
Pfeil 16.22.1 Fehlerausgabe mit »perror()«
Pfeil 16.22.2 Fehlerausgabe mit »strerror()«
Pfeil 16.23 Formatiert in einen String schreiben und formatiert aus einem String lesen – »sscanf()« und »sprintf()«
Pfeil 16.24 Byte- und wide-orientierter Stream
Pfeil 16.25 Ein fortgeschrittenes Thema
Pfeil 16.26 Low-Level-Datei-I/O-Funktionen (nicht ANSI C)
Pfeil 16.26.1 Datei öffnen – »open()«
Pfeil 16.26.2 Datei schließen – »close()«
Pfeil 16.26.3 Datei erzeugen – »creat()«
Pfeil 16.26.4 Schreiben und Lesen – »write()« und »read()«
Pfeil 16.26.5 File-Deskriptor positionieren – »lseek()«
Pfeil 16.26.6 File-Deskriptor von einem Stream – »fileno()«
Pfeil 16.26.7 Stream von File-Deskriptor – »fdopen()«


Rheinwerk Computing - Zum Seitenanfang

16.20 Pufferung einstellen – »setbuf()« und »setvbuf()« Zur nächsten ÜberschriftZur vorigen Überschrift

Eine kurze Erklärung zur Pufferung: Die Standardeinstellung ist bei ANSI-C-Compilern die Vollpufferung. Dies ist auch sinnvoller und schneller als keine Pufferung, da weniger Lese- und Schreiboperationen etwa auf der Festplatte oder dem Arbeitsspeicher stattfinden. Die Puffergröße ist abhängig vom Compiler, liegt aber meistens bei 512 und 4096 Bytes. Die Größe ist in der Headerdatei <stdio.h> mit der Konstante BUFSIZ angegeben.

Bei einer Pufferung, die zeichenweise eingestellt ist, würde ein Kopiervorgang zum Beispiel so ablaufen:

-> Lese aus Datei ein Zeichen
<- Schreibe in eine Datei ein Zeichen
-> Lese aus Datei ein Zeichen
<- Schreibe in eine Datei ein Zeichen
-> Lese aus Datei ein Zeichen
<- Schreibe in eine Datei ein Zeichen
....
usw. Zeichen für Zeichen

Bei einer Datei mit 100 Bytes wären das 100 Zugriffe zum Lesen im Wechsel mit 100 Zugriffen zum Schreiben.

Bei Vollpufferung läuft dies so: Es wird so lange gelesen, bis der Puffer voll ist (BUFSIZE), und dann wird geschrieben. Im obigen Beispiel würde bei Vollpufferung einmal gelesen und einmal geschrieben.

Um hier selbst in die Pufferung eingreifen zu können, stehen Ihnen die Funktionen setbuf() oder setvbuf() zur Verfügung.


Rheinwerk Computing - Zum Seitenanfang

16.20.1 Die Funktion »setbuf()« Zur nächsten ÜberschriftZur vorigen Überschrift

Mit der Funktion setbuf() wird einer Datei ein Dateipuffer zugeordnet. Die Syntax lautet:

#include <stdio.h>

void setbuf(FILE * restrict datei, char * restrict puffer);

Der geöffnete Stream datei erhält durch setbuf() den Puffer puffer. Die Größe des Puffers wird durch den Wert von BUFSIZ vorgegeben. Die symbolische Konstante BUFSIZ befindet sich in der Headerdatei <stdio.h>.

Wie groß BUFSIZ auf Ihrem System ist, ermitteln Sie mit folgendem Listing:

/* bufsize.c */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
   printf("Die max. Groesse des Puffers: %d\n",BUFSIZ);
   return EXIT_SUCCESS;
}

Der Wert für BUFSIZ dürfte in der Regel 256 KB, 512 KB oder auch 4096 KB betragen. Dies ist abhängig vom System und vom Compiler.

Geben Sie hingegen für puffer den NULL-Zeiger an, erfolgt die Datenübertragung ungepuffert. Das würde eine Übertragung Zeichen für Zeichen bedeuten und natürlich erheblich mehr Zeit beanspruchen, da jedes einzelne Zeichen gelesen und anschließend wieder geschrieben wird.

Sie müssen die Funktion setbuf() unmittelbar nach dem Öffnen einer Datei aufrufen – noch vor einer Lese- oder Schreiboperation.

Zur Demonstration folgt ein Listing, das gepuffertes und ungepuffertes Kopieren von Daten vergleicht. Außerdem werden dabei die Funktionen getc() und putc() zum Lesen und Schreiben verwendet, die zwar zeichenweise arbeiten, aber dennoch vom Puffer abhängig sind. Hier das Listing:

/* test_setbuffer.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DATEIGROESSE 10000000L
#define DATEI1 "test.1"
#define DATEI2 "test.2"

void copy1(char *quelle, char *ziel) {
   FILE *q,*z;
   int c;
   time_t t1 = time(NULL);

   printf("Kopiere zeichenweise mit getc() und putc()\n");
   q=fopen(quelle, "rb");
   if( q != NULL) {
      z = fopen(ziel, "wb");
      if(NULL == z) {
         fprintf(stderr,"Fehler beim Öffnen (%s)\n",ziel);
         exit(EXIT_FAILURE);
      }
   }
   else {
      fprintf(stderr, "Fehler beim Öffnen von %s\n", quelle);
      exit(EXIT_FAILURE);
   }
   while((c=getc(q)) != EOF)
      putc(c,z);
   fclose(q);
   fclose(z);

   printf("Zeit = %d sec.\n",time(NULL)-t1);
}

void copy2(char *quelle, char *ziel) {
   FILE *q,*z;
   static char puffer1[BUFSIZ];
   static char puffer2[BUFSIZ];
   int c;
   time_t t1 = time(NULL);

   printf("Gepuffertes Kopieren mit setbuf(stream,BUFSIZE)\n");
   q=fopen(quelle,"rb");
   if(q != NULL) {
      z = fopen(ziel, "wb");
      if(NULL == z) {
         fprintf(stderr,"Fehler beim Öffnen (%s)\n",ziel);
         exit(EXIT_FAILURE);
      }
   }
   else {
      fprintf(stderr, "Fehler beim Öffnen von %s\n", quelle);
      exit(EXIT_FAILURE);
   }
   setbuf(q,puffer1);
   setbuf(z,puffer2);
   while((c=getc(q)) != EOF)
      putc(c,z);
   fclose(q);
   fclose(z);
   printf("Zeit = %d sec.\n",time(NULL)-t1);
}

void copy3(char *quelle, char *ziel) {
   FILE *q,*z;
   int c;
   time_t t1 = time(NULL);

   printf("Ungepuffertes Kopieren mit setbuf(stream, NULL)\n");
   q = fopen(quelle, "rb");
   if(q != NULL) {
      z = fopen(ziel, "wb");
      if(NULL == z) {
         fprintf(stderr, "Fehler beim Öffnen (%s)\n", ziel);
         exit(EXIT_FAILURE);
      }
   }
   else {
      fprintf(stderr, "Fehler beim Öffnen von %s\n", quelle);
      exit(EXIT_FAILURE);
   }
   setbuf(q,NULL);
   setbuf(z,NULL);
   while((c=getc(q)) != EOF)
      putc(c,z);
   fclose(q);
   fclose(z);
   printf("Zeit = %d sec.\n",time(NULL)-t1);
}

void erzeuge_datei(void) {
   FILE *create = fopen(DATEI1, "wb");
   if(NULL == create) {
      fprintf(stderr, "Konnte keine Datei erzeugen\n");
      exit(EXIT_FAILURE);
   }
   fseek(create,DATEIGROESSE-1,SEEK_SET);
   putc('x',create);
   fclose(create);
}

int main(void) {
   printf("Datei %s wird erzeugt\n", DATEI1);
   erzeuge_datei();
   copy1(DATEI1,DATEI2);
   copy2(DATEI1,DATEI2);
   copy3(DATEI1,DATEI2);

   remove(DATEI1);
   remove(DATEI2);
   return EXIT_SUCCESS;
}

Abbildung 16.8 Zeitvergleiche mit gepufferter und ungepufferter Einstellung

Zuerst wird eine Datei von zehn Megabyte Größe mit der Funktion erzeuge_datei() angelegt. Anschließend wird die erzeugte Datei test.1 in die Datei test.2 kopiert, ohne die Funktion setbuf() zu verwenden (Funktion copy1()).

Als Nächstes wird die Funktion copy2() verwendet, bei der zum ersten Mal setbuf() eingesetzt wird. Als Pufferungsgröße wird hierbei die Konstante BUFSIZ verwendet. Der Zeitverbrauch ist wieder derselbe wie zuvor ohne setbuf(). Also können Sie sich setbuf() mit der Größe von BUFSIZ ersparen, da dies die Standardeinstellung für die Funktionen getc() und putc() zu sein scheint.

Als Letztes wurde die Funktion copy3() ausgeführt, bei der der Puffer auf NULL gesetzt wird. Somit wird ungepuffert kopiert. Das dauert natürlich eine Weile, da nach jedem Lesezugriff pro Byte gleich wieder ein Schreibzugriff erfolgt.

Am Ende werden diese beiden Dateien mittels remove() wieder gelöscht, damit nicht unnötig Datenmüll auf der Platte übrig bleibt.


Hinweis

Die Geschwindigkeit des Kopiervorgangs – wie im Listing demonstriert – ist nicht nur von der Power des Rechners abhängig. Einen sehr bedeutenden Anteil daran hat auch der Compiler selbst. Ich habe obiges Programm testweise mit einem anderen Compiler übersetzt, und es lief bis zu dreimal schneller.



Hinweis

Die Funktion setbuf() ist mittlerweile veraltet und wird nur noch aus Kompatibilitätsgründen beibehalten. Es empfiehlt sich, die neuere Funktion setvbuf() zur Veränderung des Dateipuffers zu verwenden.



Rheinwerk Computing - Zum Seitenanfang

16.20.2 Die Funktion »setvbuf()« topZur vorigen Überschrift

Zur Puffereinstellung kann aber auch die Funktion setvbuf() eingesetzt werden, die ähnlich wie setbuf() funktioniert. Hierzu lautet die Syntax:

#include <stdio.h>

int setvbuf(FILE * restrict datei,char * restrict puffer,int modus,
            size_t puffergroesse);

Wenn alles in Ordnung ging, liefert diese Funktion 0 zurück, andernfalls einen Wert ungleich 0. Die ersten beiden Parameter (FILE *datei,char *puffer) haben dieselbe Bedeutung wie schon bei der Funktion setbuf(). Zusätzlich stehen hier für den Parameter modus drei symbolische Konstanten zur Verfügung (siehe Tabelle 16.8).


Tabelle 16.8 Konstanten für die Einstellung des Puffers mit »setvbuf()«

Puffertyp (Modus) Bedeutung
_IOLBF

Die Datei wird zeilenweise gepuffert. Hierbei wird bei einer Lese- und Schreiboperation der Puffer gefüllt und erst übertragen, wenn ein Newline-Zeichen im Puffer vorkommt oder der Puffer voll ist.

_IONBF

Die Ein-/Ausgabe wird gar nicht gepuffert. Die Daten werden direkt aus der Datei übertragen. Die Parameter puffer und puffergroesse haben hier keinerlei Effekt.

_IOFBF

Die Ein-/Ausgabe wird voll gepuffert. Der Puffer wird komplett gefüllt, bis die Daten übertragen werden.


Falls hierbei für puffer NULL angegeben wird, alloziert die Funktion einen eigenen Speicher der Größe puffergrösse. Das hört sich komplexer an, als es ist. setbuf() ohne Pufferung verwenden Sie beispielsweise so:

setbuf(quelle,NULL);

Hiermit wurde für den Stream quelle die Pufferung abgeschaltet (ungepuffert). Mit setvbuf() würde dies so erreicht:

setvbuf(quelle, NULL, _IONBF, BUFSIZ);

Für den Stream quelle wurde der Puffer nun ebenso abgeschaltet.

Wenn Sie die Pufferung auf z. B. 50 KB einstellen wollen, um Daten vom Stream quelle zum Stream ziel zu kopieren, so ergeben sich bei setvbuf() folgende Argumente:

setvbuf(quelle, NULL, _IOFBF, 50000L);
setvbuf(ziel, NULL, _IOFBF, 50000L);

Für eine zeilenweise Pufferung könnten Sie folgende Angaben machen:

setvbuf(quelle, NULL, _IOLBF, 80);
setvbuf(ziel, NULL, _IOLBF, 80);

So werden von quelle nach ziel mindestens 80 Zeichen kopiert, oder es wird bis zum nächsten Newline-Zeichen (\n) kopiert.

Sie haben auf diese Weise mit der Funktion setvbuf() die Möglichkeit, einen Dateipuffer bestimmter Länge zuzuordnen.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: C/C++






 C/C++


Zum Rheinwerk-Shop: Einstieg in C






 Einstieg in C


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern