C-Dateiverwaltung: I/O mit fopen, fprintf, fread & fseek meistern
C-Dateiverwaltung
Dieses Tutorial führt Sie durch Datei-I/O in C, sowohl Standard- als auch Binär-Operationen mit klaren, praktischen Beispielen.
Eine Datei ist ein logischer Container auf dem Speicher eines Computers, der Daten für die langfristige Nutzung hält.
Warum Dateien verwenden?
- Daten bleiben nach Programmende erhalten, was Informationsverlust verhindert.
- Große Datensätze können einmal gespeichert und über wenige C-Befehle schnell abgerufen werden.
- Dateien können zwischen Computern ohne Modifikation verschoben werden.
Dateitypen
In C begegnen Sie zwei primären Dateitypen:
- Textdateien
- Binärdateien
Textdateien
Reine Textdateien (z. B. .txt) sind mit jedem Texteditor bearbeitbar. Sie sind einfach zu lesen, zu warten und zu übertragen, belegen jedoch mehr Speicherplatz und bieten minimale Sicherheit.
Binärdateien
Binärdateien (häufig .bin) speichern Daten als rohe Bytes (0er und 1er). Sie sind kompakt, nicht menschenlesbar und bieten bessere Datenintegrität und Sicherheit.
Kern-Dateioperationen
Unabhängig vom Typ dreht sich C-Dateiverwaltung um vier Operationen:
- Neue Datei erstellen
- Bestehende Datei öffnen
- Datei schließen
- Aus Datei lesen oder in Datei schreiben
Dateizeiger vorbereiten
Alle Dateioperationen erfordern einen FILE *-Zeiger, der auf die offene Datei verweist:
FILE *fptr;
Dateien öffnen: Erstellen und Bearbeiten
stdio.h) öffnet eine Datei und gibt einen FILE *-Zeiger zurück. Ihre Syntax lautet:
fptr = fopen("filename", "mode");
Beispielverwendung:
fopen("E:\\cprogram\\newprogram.txt", "w");
fopen("E:\\cprogram\\oldprogram.bin", "rb");
Erklärung:
newprogram.txtwird erstellt (falls nicht vorhanden) und zum Schreiben im Modus'w'geöffnet, was bestehenden Inhalt überschreibt.oldprogram.binwird zum binären Lesen im Modus'rb'geöffnet; Schreibversuche schlagen fehl.
| Modus | Bedeutung | Verhalten bei fehlender Datei |
|---|---|---|
r | Zum Lesen öffnen | Gibt NULL zurück |
rb | Zum binären Lesen öffnen | Gibt NULL zurück |
w | Zum Schreiben öffnen (überschreiben) | Erstellt Datei falls nicht vorhanden |
wb | Zum binären Schreiben öffnen (überschreiben) | Erstellt Datei falls nicht vorhanden |
a | Zum Anhängen öffnen | Erstellt Datei falls nicht vorhanden |
ab | Zum binären Anhängen öffnen | Erstellt Datei falls nicht vorhanden |
r+ | Lesen und Schreiben | Gibt NULL zurück |
rb+ | Lesen und Schreiben im Binärmodus | Gibt NULL zurück |
w+ | Lesen und Schreiben (überschreiben) | Erstellt Datei falls nicht vorhanden |
wb+ | Lesen und Schreiben im Binärmodus (überschreiben) | Erstellt Datei falls nicht vorhanden |
a+ | Lesen und Anhängen | Erstellt Datei falls nicht vorhanden |
ab+ | Lesen und binäres Anhängen | Erstellt Datei falls nicht vorhanden |
Datei schließen
Nach allen I/O-Operationen schließen Sie die Datei immer mit fclose(), um Ressourcen freizugeben und Puffer zu leeren:
fclose(fptr);
Textdatei-I/O
Textdateien werden mit fprintf() und fscanf() behandelt, den dateibasierten Entsprechungen von printf() und scanf(). Sie erfordern einen FILE *-Zeiger als erstes Argument.
Beispiel 1: In eine Textdatei schreiben
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
// Pfad für Ihr OS anpassen
fptr = fopen("C:\\program.txt", "w");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
printf("Enter a number: ");
scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
return 0;
}
Dieses Programm liest eine Ganzzahl vom Benutzer ein und schreibt sie in program.txt.
Beispiel 2: Aus einer Textdatei lesen
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
fptr = fopen("C:\\program.txt", "r");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
fscanf(fptr, "%d", &num);
printf("Value read: %d\n", num);
fclose(fptr);
return 0;
}
Die Ausführung nach dem ersten Beispiel zeigt die gespeicherte Ganzzahl an.
Zusätzliche Hilfsfunktionen wie fgetc() und fputc() folgen demselben Muster.
Binärdatei-I/O
Binärdateien werden mit fwrite() zum Schreiben und fread() zum Lesen manipuliert. Beide Funktionen akzeptieren vier Argumente: Zeiger auf Daten, Größe jedes Elements, Anzahl der Elemente und FILE *-Zeiger.
In eine Binärdatei schreiben
fwrite(addressData, sizeData, numberData, filePointer);
Beispiel 3: In eine Binärdatei schreiben mit fwrite()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "wb");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
num.n1 = i;
num.n2 = 5 * i;
num.n3 = 5 * i + 1;
fwrite(&num, sizeof(struct threeNum), 1, fptr);
}
fclose(fptr);
return 0;
}
Aus einer Binärdatei lesen
Die entsprechende fread()-Signatur spiegelt fwrite() wider:
fread(addressData, sizeData, numberData, filePointer);
Beispiel 4: Aus einer Binärdatei lesen mit fread()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
}
fclose(fptr);
return 0;
}
Dieses Programm reproduziert die in Beispiel 3 geschriebenen Daten.
Zufälliger Zugriff mit fseek()
Wenn eine Datei viele Datensätze enthält, kann das sequenzielle Durchlaufen zu einem bestimmten Eintrag ineffizient sein. fseek() bewegt den Dateizeiger an eine beliebige Position und ermöglicht direkten Zugriff.
Syntax
fseek(FILE *stream, long int offset, int whence);
stream: vonfopen()zurückgegebener Zeiger.offset: Anzahl der Bytes, die bewegt werden sollen.whence: Startpunkt –SEEK_SET,SEEK_CURoderSEEK_END.
| Konstante | Bedeutung |
|---|---|
SEEK_SET | Offset beginnt am Dateianfang. |
SEEK_CUR | Offset beginnt an der aktuellen Cursorposition. |
SEEK_END | Offset beginnt am Dateiende. |
Beispiel 5: Rückwärts-Lesen mit fseek()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("Error opening file\n");
exit(EXIT_FAILURE);
}
// Zum letzten Datensatz springen
fseek(fptr, -sizeof(struct threeNum), SEEK_END);
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
// Zwei Datensätze zurückspringen (aktueller + einer mehr), um vorherigen Eintrag zu lesen
fseek(fptr, -2 * sizeof(struct threeNum), SEEK_CUR);
}
fclose(fptr);
return 0;
}
Dieses Snippet demonstriert, wie man eine Binärdatei in umgekehrter Reihenfolge durchläuft, beginnend beim letzten Datensatz.
C Sprache
- Java-Dateioperationen mit java.io meistern – Erstellen, Lesen, Schreiben & Löschen
- STL-Dateien verstehen: Das Rückgrat des 3D-Drucks
- Datei-E/A in Verilog meistern: Öffnen, Lesen, Schreiben und Schließen
- Datei-I/O in C meistern: Erstellen, Öffnen & Verwalten von Dateien
- C-Header-Dateien verstehen: Typen, Verwendung und Best Practices
- Fehlerbehandlung in C meistern: Best Practices & Techniken
- C++ Datei-I/O: Lesen & Schreiben mit fstream
- C++ Signalverarbeitung meistern: Sichere Interrupt-Verwaltung und saubere Programmausführung
- C# Exception Handling: try, catch, finally, throw & Best Practices
- C# Datei-E/A: Lesen, Schreiben & Stream-Verwaltung