Dateizugriffe in C [Dateizugriffe in C] (Dateizugriffe in C), Lektion, Seite 722297
https://www.purl.org/stefan_ram/pub/dateizugriffe_in_c (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram

Dateizugriffe in C

Zeilenenden

Wenn das Zeilenendzeichen »'\n'« in eine Textdatei geschrieben wird, so wird unter jeder Umgebung das Codemuster ausgegeben, das unter dieser Umgebung eine Zeile abschließt. Dies können unter manchen Umgebungen auch mehrere Byte sein.

»puts«

Mit »puts« können Texte, die dem Programmierer nicht bekannt sind, sicherer ausgegeben werden als mit einem naiven Aufruf von »printf«, weil »puts« eventuell in diesen Texten vorkommende Prozentzeichen nicht interpretiert. Außerdem fügt »puts« immer ein Zeilenende an. Es kann aber nur Text ausgeben, keine Zahlen oder anderes.

Synopsis
#include <stdio.h>
int puts( const char * s );
Wirkung Ausgabe des Textes »s« und eines Zeilenendes.
Wert »EOF« bei Fehler, ein nichtnegativer Wert sonst.
Beispiel »puts( "alpha" );« gibt den Text »alpha« aus.

»stdin«

Aus einem Strom können unter Umständen Daten gelesen oder es können Daten in ihn geschrieben werden. Ein Strom  kann beispielsweise eine geöffnete Datei sein.

Der Strom »stdin« ist der Standardstrom für Eingaben an das Programm.

Synopsis
#include <stdio.h>
FILE * stdin;
Beispiel »printf( "%p", stdin )«.

»ferror«

Mit »ferror« kann der Fehlerindikator eines Stromes ermittelt werden.

Synopsis
#include <stdio.h>
int ferror( FILE *stream );
Wirkung Ausgabe des Textes »s« und eines Zeilenendes.
Wert Ergibt 0, genau dann wenn der Fehlerindikator des Stromes »stream« nicht gesetzt ist.
Beispiel »printf( "%d\n", ferror( stdin ));«.

»feof«

Mit »feof« kann der Endindikator eines Stromes ermittelt werden.

Synopsis
#include <stdio.h>
int feof( FILE *stream );
Wert Ergibt 0, genau dann wenn der Dateiendindikator nicht gesetzt ist.
Beispiel »if( !feof( stdin ))copy();«.

»fgetc«

Mit »fgetc« kann ein Zeichen wie mit »getchar« eingelesen werden, nur daß dabei auch noch der Quellstrom angegeben werden kann.

Synopsis
#include <stdio.h>
int fgetc( FILE * stream );
Wirkung Einlesen eines Zeichens vom Strom »stream«. Setzen des Fehlerindikators bei einem Fehler.
Wert Das eingelesene Zeichen oder »EOF« bei einem Fehler oder beim erschöpftem Strom (beispielsweise Dateiende).
Beispiel »while( EOF !=( c = fgetc( stdin ))append( c );«.

»getc« kann ähnlich verwendet werde, könnte aber als Makro definiert sein, so daß Argumente eventuell wiederholt ausgewertet werden könnten.

»stdout«

Der Strom »stdin« ist der Standardstrom für Ausgaben des Programms.

Synopsis
#include <stdio.h>
FILE * stdout;
Beispiel »printf( "%p", stdout )«.

»stderr«

Der Strom »stderr« ist der Standardstrom für Fehlerberichte des Programms.

Bei Bedarf wird es so auch ermöglicht, die Ausgaben von Ergebnisses und Fehlerberichte getrennt zu behandeln. Wenn die Standardausgabe eines Prozesses in eine Datei umgelenkt wurde, können die Fehlerbericht so beispielsweise immer noch auf der Konsole gesehen werden.

Synopsis
#include <stdio.h>
FILE * stderr;
Beispiel »printf( "%p", stderr )«.

»fputc«

Mit »fputc« kann ein Zeichen wie mit »putchar« ausgegeben werden, nur daß dabei auch noch der Zielstrom angegeben werden kann.

Synopsis
#include <stdio.h>
int fputc( int c, FILE * stream );
Wirkung Ausgabe des nach »unsigned char« gewandelten Zeichens »c« auf den Strom »stream«. Setzen des Fehlerindikators bei einem Fehler.
Wert Das ausgegebene Zeichen »c« oder »EOF« bei einem Fehler oder beim erschöpftem Strom (beispielsweise Dateiende).
Beispiel »fputc( '\n', stdout );«.

»putc« kann ähnlich verwendet werde, könnte aber als Makro definiert sein, so daß Argumente eventuell wiederholt ausgewertet werden könnten.

Bei dieser Funktion wird der Strom nicht wie sonst oft üblich als erstes Argument angegeben, sondern als letztes Argument.

»fflush«

Mit »fflush« kann der Puffer eines Ausgabestroms geleert werden.

Synopsis
#include <stdio.h>
int fflush( FILE * stream );
Wirkung Leeren der Puffer des Ausgabestroms »stream«. Der Fehlerindikator des Stroms wird gesetzt, falls es dabei zu einem Fehler kam.
Wert 0 oder »EOF« bei einem Fehler.
Beispiel »fflush( stdout );«.

Der Versuch Eingabepuffer  mit »fflush« zu leeren ist ein häufiger Fehler. Die Auswertung von »fflush( stdin )« hat tatsächlich undefiniertes Verhalten.

»fprintf«

Eine Erweiterung von »printf« um einen ersten Parameter mit einem Ausgabestrom.

Synopsis
#include <stdio.h>
int fprintf( FILE * restrict stream, const char * restrict format, ... );
Hinweis Das Schlüsselwort »restrict« kann hier und im folgenden bei Verwendung von ANSI-C  ignoriert werden.
Beispiel »fprintf( stderr, "Division by zero." );«.

»fscanf«

Eine Erweiterung von »scanf« um einen ersten Parameter mit einem Eingabestrom.

Synopsis
#include <stdio.h>
int fscanf(FILE * restrict stream, const char * restrict format, ...);
Beispiel »fscanf( stdin, "%d", &i );«.

»fputs«

Eine Erweiterung von »puts« um einen ersten Parameter mit einem Ausgabestrom, die außerdem kein  zusätzliches Zeilenendzeichen ausgibt (wie dies »puts« ja macht).

Synopsis
#include <stdio.h>
int fputs( const char * s, FILE * stream );

Bei dieser Funktion wird der Strom nicht wie sonst oft üblich als erstes Argument angegeben, sondern als letztes Argument.

»fopen«

Erlaubt das Eröffnen weiterer Ströme an Hand eines Pfades und eines Modus. Solch ein Strom kann dann wie die schon vorhandenen Standardströme »stdout«, »stderr« und »stdin« genutzt werden.

Die wichtigsten Modi für den Anfang:

»"r"« Lesezugriff auf Textdatei

»"w"« Schreibzugriff auf Textdatei

»"rb"« Lesezugriff auf Binärdatei

»"wb"« Schreibzugriff auf Binärdatei

Synopsis
#include <stdio.h>
FILE *fopen( const char * restrict filename, const char * restrict mode );
Wirkung Öffnen des angegebenen Pfades »filename« mit dem angegebenen Modus »mode«.
Wert Ein Strom zum Zugriff auf den geöffneten Pfad oder 0, falls der Versuch des Öffnens scheiterte.
Beispiel »if( source = fopen( "test.c", "r" ))process( source );«.

Diese Funktion ist lediglich ein Versuch, deswegen kann nach ihrem Aufruf nicht einfach immer vom Erfolg ausgegangen werden. Sie liefert außerdem im Erfolgsfall eine Resource zurück, die dann wieder (wie weiter unten beschrieben) zurückgegeben werden muß.

»fclose«

Schließen eines vom Programm geöffneten Stromes.

Synopsis
#include <stdio.h>
int fclose( FILE *stream );
Wirkung Eventuelle Ausgabepuffer des Stroms »stream« werden geschrieben und die zu ihm gehörende geöffnete Datei wird geschlossen.
Wert 0 bei Erfolg, EOF bei Scheitern.
Beispiel »if( fclose( source ))error();«.

»fread«

Lesen binärer Daten.

Synopsis
#include <stdio.h>
size_t fread
( void * restrict ptr,
size_t size,
size_t nmemb,
FILE * restrict stream );
Wirkung Liest »nmemb« Blöcke der Größe »size« vom Strom »stream« in den Puffer »ptr«.
Wert Anzahl der erfolgreich gelesenen Blöcke.
Beispiel Um 1000 Zeichen zu lesen: »fread( p, 1000, 1, f )« scheitert falls weniger als 1000 Zeichen vorhanden sind, »fread( p, 1, 1000, f )« liest dann so viele Zeichen, wie vorhanden sind.

»fwrite«

Schreiben binärer Daten.

Synopsis
#include <stdio.h>
size_t fwrite
( const void * restrict ptr,
size_t size,
size_t nmemb,
FILE * restrict stream );
Wirkung Schreibt »nmemb« Blöcke der Größe »size« vom Puffer »ptr« in den Strom »stream«.
Wert Anzahl der erfolgreich geschriebenen Blöcke.
Beispiel »fwrite( p, 1000, 1, f )«.

Beispiel und Übung

Das folgende Programm kopiert eine Datei »source« nach »target« und verwendet dazu einen größeren Puffer. Das Kopieren sollte dadurch schneller erfolgen als bei zeichenweisem Kopieren mit getc und putc.

Vorsicht Dieses Programm löscht eine eventuell vorhandene Datei namens »target« in dem Verzeichnis, in dem es gestartet wird.

#include <stdio.h>
#include <stdlib.h> int main( void )
{ size_t buffsize = 16384; // eventuelle eckige Klammer in dieser Zeile löschen
FILE * source = fopen( "source", "rb" );
FILE * target = fopen( "target", "wb" );
unsigned char * buff = malloc( buffsize );
size_t read = fread( buff, 1, buffsize, source );
fwrite( buff, read, 1, target );
return EXIT_SUCCESS; }
/    Übung (eine gute Aufgabe zum Üben der Ressourcenverwaltung!)
Das direkt voranstehende Programmbeispiel enthält noch einige Mängel, einige davon sind Absicht. Die Übungsaufgabe besteht nun darin, dieses Kopierprogramm in ein bessereres und robustereres Kopierprogramm umzuschreiben, dessen Quellkode auch noch möglichst übersichtlich sein soll. Dazu folgen hier nun einige Hinweise und Anmerkungen:
o Das Öffnen von Dateien kann auch scheitern, und das Programm sollte dann nicht einfach so weitermachen, als sei das Öffnen gelungen.
o Das Anfordern von Speicher kann auch scheitern, und das Programm sollte dann nicht einfach so weitermachen, als sei der Speicher erhalten worden.
o Einmal geöffnete Dateien sollten auch wieder geschlossen werden (und zwar frühestmöglich, sobald sie nicht mehr gebraucht werden).
o Erhaltener Speicher sollte wieder freigegeben werden (und zwar frühestmöglich, sobald er nicht mehr gebraucht wird). Das ist hier zwar nicht so wichtig, weil das Programm nur kurz läuft, aber man soll sich vorstellen, daß die Funktion »main« eine Bibliotheksfunktion wäre, die auch in einem längerlaufenden Programm wiederholt benutzt werden können sollte.
o Das Programm kopiert nur bis zu 16384 Byte. Es sollte das Lesen und Schreiben mit »fread« und »fwrite« notfalls wiederholen, um so auch längere Dateien kopieren zu können. (Die Puffergröße von 16384 Byte wurde willkürlich festgelegt und kann auch verändert werden.)
o Wo dies vorteilhaft ist, sollte »const« verwendet werden.
Besonders schön wäre dann auch noch eine Umsetzung der folgenden Idee
o Das nach Berücksichtigung einiger der obigen Hinweise entstandene Programm wird übersichtlich auf verschiedene Funktionen aufgeteilt, so daß inhaltlich zusammengehörige Programmteile jeweils in einer Funktion zusammengefaßt werden. (Kann schwierig sein. Falls keine gute Lösung gefunden werden kann, besser ganz sein lassen.)
o Die guten Prinzipien der strukturierten Programmierung sollten stets beachtet werden: Demgemäß sollte jeder Block nur einen Eingang und einen Ausgang haben, es sollten also keine Sprungbefehle verwendet werden (jedenfalls kein »goto«, allenfalls »return«, »break« oder »continue«).
o Außerdem sollte das Programm weiterhin so kurz wie möglich sein, unnötige Programmteile und Wiederholungen von Codeteilen sollten so weit wie möglich vermieden werden (lassen sich aber nicht immer ganz vermeiden)
o Die weiter oben gegebenen Empfehlungen zur Ressourcenbehandlung sollten beachtet werden. Außerdem empfiehlt sich auch die Beachtung des untenstehenden „Transaktionsprinzips“.
Zusätzlich könnten auch noch weitere wünschenswerte Eigenschaften realisiert werden:
o Bei Fehlern wird von »main« »EXIT_FAILURE« zurückgegeben.
o Auch ein Aufruf von »fclose« kann scheitern, so daß auch dieser beim Ermitteln des Fehlerstatus berücksichtigt werden sollte.
o Die verwendeten Ströme werden auf Fehler untersucht.
o Vielleicht wurden noch andere Mängel oder Verbesserungsmöglichkeiten des Programms übersehen. Auch diese könnten gegebenenfalls berücksichtigt werden.

Transaktionsprinzip Wenn ein untergeordneter Programmteil mehrere Ressourcen anfordern und bereitstellen soll, dann sollte er am Ende entweder alle oder keine bereitgestellt haben. Falls er also schon einige Ressourcen erhalten hat, sollte er bei einem Scheitern einer Anforderung die bisher schon erhaltenen Ressourcen wieder freigeben.

/    Dateigröße
Ein Programm ermittelt die Größe einer angegebenen Datei einmal in Byte (Binärdatei) und einmal in Zeichen (Textdatei), indem ermittelt wird, wie oft ein Byte beziehungsweise Zeichen gelesen werden kann. (Irrglaube: fseek an das Ende einer Binärdatei erlaubt immer eine portable  Ermittlung der Dateigröße mit ftell.)

Eigenschaften von Implementationen

[Neu]

ISO/IEC 9899:1999 (E)
5.1.2.2.3 Program termination
[#1] If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;
7.20.4.3 The exit function (…)
All open streams with unwritten buffered data are flushed, all open streams are closed, and all files created by the tmpfile function are removed.
ISO/IEC 9899:1999 (E)
J.3 Implementation-defined behavior
[#1] A conforming implementation is required to document its choice of behavior in each of the areas listed in this subclause. The following are implementation-defined: (…)
J.3.12 Library functions
[#1] (…)
— Whether the last line of a text stream requires a terminating new-line character (7.19.2). (…)
— The output for %p conversion in the fprintf or fwprintf function (7.19.6.1, 7.24.2.1). (…)
— Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed when the abort or _Exit function is called (7.20.4.1, 7.20.4.4).

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722297 stefan_ram:722297 Dateizugriffe in C Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722297, slrprddef722297, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten.
https://www.purl.org/stefan_ram/pub/dateizugriffe_in_c