HOWTO · C
Datei-Umleitung in C verwenden
Dieser Artikel demonstriert, wie man eine Dateiumleitung in C verwendet
Auf dieser Seite
Um die Ein- oder Ausgabe eines C-Programms über die Kommandozeile umzuleiten, verwenden Sie die Shell-Operatoren <, > und >>. Die Shell verbindet die Standardstreams des Programms mit Dateien. C-Code kann stattdessen mit fopen eine benannte Datei öffnen oder mit freopen einen Standardstream ändern. Diese Möglichkeiten dienen zwar demselben Zweck, Daten zu verarbeiten, sind aber unterschiedliche Vorgänge.
Datei-Umleitungen in C verstehen
Ein C-Prozess startet mit drei Standardstreams: stdin für Eingaben, stdout für normale Ausgaben und stderr für Diagnosemeldungen. Eine Shell verbindet sie normalerweise mit dem Terminal. Eine Umleitung ändert diese Verbindungen beim Start des Programms. Daher kann das Programm weiterhin fgets, printf oder fprintf(stderr, ...) aufrufen, ohne wissen zu müssen, ob ein Stream auf ein Terminal oder eine Datei verweist.
fopen dagegen gibt einen separaten FILE * zurück, aus dem Ihr Code direkt liest oder in den er schreibt. Verwenden Sie es, wenn das Programm Dateien selbst auswählen, mehrere Dateien gleichzeitig bearbeiten oder deren Lebensdauer steuern muss. Eine Shell-Umleitung eignet sich, wenn der Aufrufer das Eingabeziel oder Ausgabeziel für einen Programmlauf bestimmen soll.
Programmausgabe mit > und » umleiten
Dieses kleine Programm schreibt eine Zeile nach stdout:
Führen Sie dieses Beispiel aus:
Der Quelltext und sichtbare Beschriftungen oder Meldungen innerhalb der unveränderten Codebeispiele bleiben auf Englisch.
#include <stdio.h>
int main(void) {
puts("Report complete");
return 0;
}
Die Zeile des Programms wird nach stdout geschrieben; ein Laufzeitprotokoll ist für dieses Beispiel nicht angegeben. Kompilieren Sie es als report und führen Sie anschließend ./report > report.txt aus, um report.txt anzulegen oder zu überschreiben. Mit ./report >> report.txt hängen Sie die Ausgabe stattdessen an. Der Operator > kürzt ein vorhandenes Ziel, bevor das Programm startet; >> schreibt am Dateiende weiter. Shell-Syntax und verfügbare Compilerbefehle unterscheiden sich je nach Plattform.
Die Shell öffnet das umgeleitete Ziel. Schlägt das Öffnen fehl, meldet die Shell das Problem und startet das Programm normalerweise nicht. Das Programm kann diesen Fehler nicht als fopen-Fehler erkennen, da es das Ziel nicht selbst geöffnet hat. Um Diagnosemeldungen getrennt zu speichern, verwenden Sie ./report > report.txt 2> errors.txt; 2> leitet den konventionellen Dateideskriptor für stderr um.
Programmeingabe mit < umleiten
Lesen Sie von stdin, wenn der Aufrufer die Eingabequelle auswählen soll. Dieses Programm liest Zeilen, bis die umgeleitete Datei das Dateiende erreicht:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
#include <stdio.h>
int main(void) {
char line[128];
while (fgets(line, sizeof line, stdin) != NULL) {
if (fputs(line, stdout) == EOF) {
perror("writing stdout");
return 1;
}
}
if (ferror(stdin)) {
perror("reading stdin");
return 1;
}
return 0;
}
Kompilieren Sie das Programm als copy-input und führen Sie dann ./copy-input < input.txt aus. fgets liest höchstens ein Zeichen weniger als die Pufferkapazität, fügt ein abschließendes Nullzeichen hinzu und behält einen Zeilenumbruch bei, falls einer eingelesen wurde. Eine lange Zeile kann deshalb in mehreren Teilen zurückgegeben werden. Prüfen Sie nach der Schleife ferror, um einen Lesefehler vom normalen Dateiende zu unterscheiden. Das Verhalten des Beispiels ergibt sich aus den gezeigten C-Streamoperationen; eine beobachtete Ausgabe ist hier nicht angegeben.
Standardstreams innerhalb eines C-Programms umleiten
Wenn das Programm selbst ein Ziel auswählen muss, kann freopen einen Standardstream erneut öffnen. Die Funktion erhält einen Pfad, einen Modus wie "w" oder "a" und den zu öffnenden Stream. Beispielsweise leitet freopen("run.log", "a", stdout) die nachfolgenden Standardausgaben so um, dass sie an run.log angehängt werden. Prüfen Sie den Rückgabewert, bevor Sie schreiben: Bei einem Fehler gibt die Funktion NULL zurück. Dadurch wird der Prozessstream geändert; fopen hingegen liefert einen zusätzlichen Stream, während stdout unverändert bleibt.
Verwenden Sie diese Möglichkeit, wenn die Umleitung zum Verhalten des Programms gehören soll. Soll der Aufrufer das Ziel bestimmen, lassen Sie stdout unverändert und verwenden Sie > oder >>. freopen gehört zum C-Standard, aber Einzelheiten zum erneuten Öffnen eines Streams nach einem Fehler können von der Implementierung abhängen. Behandeln Sie ein Ergebnis von NULL als Fehler und fahren Sie nicht so fort, als wäre die Umleitung gelungen.
Fehler behandeln und den passenden Ansatz wählen
Prüfen Sie jeden Vorgang, der fehlschlagen kann. Kontrollieren Sie fopen und freopen, bevor Sie den zurückgegebenen Stream verwenden, prüfen Sie Ausgabefunktionen wie fprintf oder fputs auf Fehler und kontrollieren Sie fclose, wenn es wichtig ist, dass gepufferte Ausgaben die Datei erreicht haben. In Eingabeschleifen kann ein Rückgabewert NULL von fgets entweder Dateiende oder einen Lesefehler bedeuten; mit ferror unterscheiden Sie beides. perror kann eine Betriebssystemmeldung zu einem Fehler ausgeben, der mit dem aktuellen errno zusammenhängt.
Leiten Sie die Größe eines Zeilenpuffers nicht aus der gemeldeten Dateilänge in Bytes ab: Die Eingabe kann von einer Pipe oder einem Terminal stammen, und eine Zeile kann länger sein als der gewählte Puffer. Ein fester Puffer mit wiederholten Aufrufen von fgets eignet sich, wenn die Verarbeitung in Teilstücken akzeptabel ist. Für eine beliebig lange logische Zeile können Sie den Puffer beim Eintreffen weiterer Teile vergrößern und dabei Grenzen für Speicherzuweisung und Arithmetik prüfen. Alternativ können Sie eine plattformspezifische Funktion zum zeilenweisen Lesen verwenden und deren Einschränkungen bei der Portabilität angeben.
Verwenden Sie Shell-Umleitungen, um die Standardstreams eines Programmlaufs zu verbinden, fopen, um in C eine zusätzliche Datei zu verwalten, und freopen, wenn das Programm selbst einen Standardstream ersetzen muss. Lassen Sie Diagnosemeldungen auf stderr, wenn die normale Ausgabe umgeleitet wird, und prüfen Sie Fehler auf der Ebene, auf der der jeweilige Vorgang stattfindet.