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

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 18 Ein-/Ausgabe-Funktionen
  gp 18.1 Was ist eine Datei?
  gp 18.2 Formatierte und unformatierte Ein-/Ausgabe
  gp 18.3 Streams
  gp 18.4 Höhere Ein-/Ausgabe-Funktionen
  gp 18.5 Datei (Stream) öffnen – fopen
    gp 18.5.1 Modus für fopen()
    gp 18.5.2 Maximale Anzahl geöffneter Dateien – FOPEN_MAX
  gp 18.6 Zeichenweise Lesen und Schreiben – getchar und putchar
    gp 18.6.1 Ein etwas portableres getch()
  gp 18.7 Zeichenweise Lesen und Schreiben – putc/fputc und getc/fgetc
  gp 18.8 Datei (Stream) schließen – fclose
  gp 18.9 Formatiertes Einlesen/Ausgeben von Streams mit fprintf und fscanf
  gp 18.10 Standard-Streams in C
    gp 18.10.1 Standard-Streams umleiten
  gp 18.11 Fehlerbehandlung von Streams – feof, ferror und clearerr
  gp 18.12 Gelesenes Zeichen in die Eingabe zurück-schieben – ungetc
  gp 18.13 (Tastatur-)Puffer leeren – fflush
    gp 18.13.1 Pufferung
  gp 18.14 Stream positionieren – fseek, rewind und ftell
  gp 18.15 Stream positionieren – fsetpos, fgetpos
  gp 18.16 Zeilenweise Ein-/Ausgabe von Streams
    gp 18.16.1 Zeilenweise Lesen mit gets/fgets
    gp 18.16.2 Zeilenweise Schreiben mit puts/fputs
    gp 18.16.3 Zeilenweise Einlesen vom Stream mit getline() (nicht ANSI C)
    gp 18.16.4 Rezepte für zeilenweises Einlesen und Ausgeben
  gp 18.17 Blockweise Lesen und Schreiben – fread und fwrite
    gp 18.17.1 Blockweises Lesen – fread()
    gp 18.17.2 Blockweises Schreiben – fwrite()
    gp 18.17.3 Big-Endian und Little-Endian
  gp 18.18 Datei (Stream) erneut öffnen – freopen
  gp 18.19 Datei löschen oder umbenennen – remove und rename
    gp 18.19.1 remove()
    gp 18.19.2 rename()
  gp 18.20 Pufferung einstellen – setbuf und setvbuf
  gp 18.21 Temporäre Dateien erzeugen – tmpfile und tmpnam
    gp 18.21.1 mkstemp() – Sichere Alternative für Linux/UNIX (nicht ANSI C)
  gp 18.22 Fehlerausgabe mit strerror und perror
  gp 18.23 Formatiert in einem String schreiben und formatiert aus einem String lesen – sscanf und sprintf
  gp 18.24 Fortgeschrittenes Thema
  gp 18.25 Low-Level-Datei-I/O-Funktionen (nicht ANSI C)
  gp 18.26 Datei öffnen – open
  gp 18.27 Datei schließen – close
  gp 18.28 Datei erzeugen – creat
  gp 18.29 Schreiben und Lesen – write und read
  gp 18.30 File-Deskriptor positionieren – lseek
  gp 18.31 File-Deskriptor von einem Stream – fileno
  gp 18.32 Stream von File-Deskriptor – fdopen


Galileo Computing - Zum Seitenanfang

18.20 Pufferung einstellen – setbuf und setvbuf  toptop

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

#include <stdio.h>
void setbuf(FILE *datei, char *puffer);

Der geöffnete Stream datei erhält durch setbuf() den Dateipuffer puffer. Dieser muss die Länge BUFSIZ haben. Die symbolische Konstante BUFSIZ befindet sich in der Headerdatei <stdio.h>.

Wie groß BUFSIZ auf Ihrem System ist, kann mit folgendem Listing ermittelt werden:

/* 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 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, welches gepuffertes und ungepuffertes Kopieren von Daten vergleicht. Außerdem werden dabei die Funktionen getc() und putc() zum Lesen und Schreiben verwendet, welche 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
Hier klicken, um das Bild zu Vergrößern

Abbildung 18.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. Obiges Programm wurde mit einem anderen Compiler übersetzt und lief bis zu dreimal schneller.



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


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

#include <stdio.h>
int setvbuf(FILE *datei,char *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:


Tabelle 18.8   Konstanten für die Einstellung des Puffers mit setvbuf()

Puffertyp (modus) Bedeutung
_IOLBF Datei wird zeilenweise gepuffert
_IONBF Ein-/Ausgabe wird gar nicht gepuffert
_IOFBF Ein-/Ausgabe wird voll gepuffert

Falls hierbei für puffer NULL angegeben wird, alloziiert die Funktion einen eigenen Speicher der Größe puffergrösse. Das hört sich komplexer an als es ist. setbuf() ohne Pufferung verwenden Sie bspw. 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.

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
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.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de