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.9 Formatiertes Einlesen/Ausgeben von Streams mit fprintf und fscanf  toptop

fprintf() und fscanf() sind die dateiorientierten Gegenstücke zu den Funktionen printf() und scanf(). Hierzu die Syntax:

#include <stdio.h>
int fprintf(FILE *f, const char *format, ...);
int fscanf(FILE *f, const char *format, ...);

Natürlich würde mit dem Folgenden

fscanf(stdin, "%d", &x);
fprintf(stdout, "Hallo Welt\n");

dasselbe erreicht wie mit

scanf("%d", &x);
printf("Hallo Welt\n");

Beide Schreibweisen, Lesen bzw. Schreiben, formatiert auf die Streams stdin bzw. stdout. fprintf() werden gern benutzt, um durch den Stream stderr eine Meldung auf die Standardfehlerausgabe (Bildschirm) ungepuffert auszugeben.

Ein klassischer Fall von fprintf() und fscanf() ist das formatierte Einlesen einer CSV-Datei, die Sie mit Tabellenkalkulationsprogrammen erzeugen und ansehen können. Das Thema wurde in Kapitel 13, Arrays, bereits einmal erwähnt.

Folgende CSV-Log-Datei soll protokolliert werden. Darin steht, wer, wann und wie lange am System eingeloggt war:

20:23,12.11.2001,20:50,12.11.2001,Pinguin
12:13,13.11.2001,15:29,13.11.2001,root
16:33,13.11.2001,20:23,13.11.2001,Mr.X
23:11,13.11.2001,01:12,14.11.2001,root
10:22,14.11.2001,12:14,14.11.2001,Spock
16:33,14.11.2001,20:21,14.11.2001,Scotty

Die Kommas stellen dabei Trennzeichen dar. Folgende Variablen werden benötigt:

Uhrzeit eingeloggt, Datum, Uhrzeit ausgeloggt, Datum, User

Der Name dieser Datei sei »log.csv«. Um diese Datei auszulesen, sollen die beiden Funktionen fprintf() und fscanf() eingesetzt werden. Hier der Quellcode zum Einlesen und Ausgeben der Log-Datei:

/* csv_log.c */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
   FILE *CSV;
   int login_hour, login_min;
   int date_day, date_mon, date_year;
   char name[40];
   int logout_hour, logout_min;
   int date_dayx, date_monx, date_yearx;
   if(argc < 2) {
      fprintf(stderr, "Verwendung : %s datei.csv\n", *argv);
      return EXIT_FAILURE;
   }
   CSV = fopen(argv[1], "r");
   if(NULL == CSV) {
      fprintf(stderr, "Fehler beim Oeffnen ...\n");
      return EXIT_FAILURE;
   }
   /* Nun lesen Sie formatiert von der Datei ein ... */
   while((fscanf(CSV,"%d:%d,%d.%d.%d,%d:%d,%d.%d.%d,%s\n",
      &login_hour,&login_min,&date_day,&date_mon,&date_year,
      &logout_hour,&logout_min,&date_dayx,&date_monx,
      &date_yearx,name)) != EOF )
       fprintf(stdout,"User:%s\nLogin um:%d:%d Uhr am %d.%d.%d\n"
                      "Logout um : %d:%d Uhr am %d.%d.%d\n\n",
         name,login_hour,login_min,date_day,date_mon,date_year,
         logout_hour,logout_min,date_dayx,date_monx, date_yearx);
   return EXIT_SUCCESS;
}

Meistens lässt sich das Einlesen solcher Dateien allerdings nicht so leicht realisieren wie hier dargestellt. Folgendes Beispiel ist da schon wesentlich komplexer:

20:23,12.11.2001,"pinguin",20:50,12.11.2001

Versuchen Sie es zunächst ruhig selbst, diese Zeile mit fscanf() einzulesen. Das Problem liegt in diesem Beispiel beim String pinguin und den doppelten Hochkommata. Hier die Möglichkeit, wie der User pinguin ohne Gänsefüßchen ausgelesen wird:

char begrenzer;
...
while((fscanf(CSV,"%d:%d,%d.%d.%d,\"%[^'\"]%c,%d:%d,%d.%d.%d\n",
          &login_hour,&login_min,&date_day,&date_mon,&date_year,
          name,&begrenzer,&logout_hour,&logout_min,
          &date_dayx,&date_monx,&date_yearx)) != EOF )

Auf den ersten Blick mag dies zwar logisch sein, aber darauf muss man erst einmal kommen. Zwar ist dieser Ansatz, CSV-Dateien einzulesen, schon recht praktisch, doch vollkommen inflexibel. Das Programm liest nur CSV-Dateien aus, deren Anordnung Sie kennen. Das würde heißen, für jede CSV-Datei müssten Sie den Code ändern, damit dieser wie eine Schablone in seine Form passt.

Gut eignet sich auch fprintf() zum Erstellen von dynamischen Textdateien. Hierzu ein Beispiel, wie Sie dynamisch Webseiten erstellen können. Dafür wird zuvor einfach der Text2HTML-Konverter aus dem vorigen Abschnitt erweitert:

/* txt2html.c */
#include <stdio.h>
#include <stdlib.h>
void html_head(FILE *ziel) {
   fprintf(ziel, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD"
                 " HTML 4.0 Transitional//EN\">\n");
   fprintf(ziel,"<html><head><title>Test-Webseite"
                "</title></head><body>\n");
   fprintf(ziel,"<pre>\n");
   fprintf(ziel,"<p style=\"margin-right:0.8cm; "
                " margin-left:0.5cm\" align=\"justify\">\n");
}
void html_end(FILE *ziel) {
   fprintf(ziel,"</pre></p></body></html>\n");
}
void sonderzeichen(int nchars, char *tag, FILE *ziel) {
   int i;
   char zeichen;
   for(i = 0; i < nchars; i++) {
      zeichen = tag[i];
      putc(zeichen, ziel);
   }
}
int main(int argc, char **argv) {
   FILE *q, *z;
   int zeichen;
   if(argc < 3) {
      printf("Benutzung : %s quelle ziel\n",*argv);
      return EXIT_FAILURE;
   }
   q = fopen(argv[1], "r");
   z = fopen(argv[2], "w");
   if(q == NULL || z == NULL) {
      printf("Fehler bei fopen() ... ");
      return EXIT_SUCCESS;
   }
   /* Kopfzeile für HTML-Dokument */
   html_head(z);
   while( (zeichen=getc(q)) != EOF) {
      if(zeichen=='<')
         sonderzeichen(4,"&lt;", z);
      else if(zeichen=='>')
         sonderzeichen(4,"&gt;", z);
      else if(zeichen=='\"')
         sonderzeichen(6,"&quot;",z);
      else if(zeichen=='&')
         sonderzeichen(5,"&amp;",z);
      else if(zeichen=='ä')
         sonderzeichen(6 ,"&auml;",z);
      else if(zeichen=='Ä')
         sonderzeichen(6 ,"&Auml;",z);
      else if(zeichen=='ö')
         sonderzeichen(6 ,"&ouml;",z);
      else if(zeichen=='Ö')
         sonderzeichen(6 ,"&Ouml;",z);
      else if(zeichen=='ü')
         sonderzeichen(6 ,"&uuml;",z);
      else if(zeichen=='Ü')
         sonderzeichen(6 ,"&Uuml;",z);
      else if(zeichen=='ß')
         sonderzeichen(6 ,"&szlig;",z);
      else if(zeichen=='\n') /* Zeilenumbruch */
         sonderzeichen(4, "<br>", z);
      else if(zeichen==' ')  /* Leerzeichen */
         sonderzeichen(6, "&nbsp;", z);
      else
         putc(zeichen, z);
   }
   /* Ende von HTML-Datei */
   html_end(z);
   return EXIT_SUCCESS;
}

Geben Sie nun in der Kommandozeile Folgendes ein (der Programmname sei t2html):

t2html myfile.txt myfile.hmtl

Jetzt finden Sie im Verzeichnis eine HTML-Datei namens myfile.html, die aus der Datei myfile.txt mit dem Programm t2html erzeugt wurde. Diese HTML-Datei können Sie nun mit Ihrem Lieblingsbrowser öffnen und ansehen.

 << 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