C Bestandsbehandeling: I/O onder de knie krijgen met fopen, fprintf, fread en fseek
C Bestandsbehandeling
Deze tutorial begeleidt je door bestands-I/O in C, met standaard en binaire operaties met duidelijke, praktische voorbeelden.
Een bestand is een logische container op de opslag van een computer die data voor langdurig gebruik bevat.
Waarom bestanden gebruiken?
- Data blijft bestaan na programma-einde, wat verlies van informatie voorkomt.
- Grote datasets kunnen één keer opgeslagen en snel benaderd worden via een paar C-commando's.
- Bestanden kunnen tussen computers verplaatst worden zonder wijziging.
Typen bestanden
In C kom je twee primaire bestandstypen tegen:
- Tekstbestanden
- Binaire bestanden
Tekstbestanden
Plain-text bestanden (bijv. .txt) zijn bewerkbaar met elke teksteditor. Ze zijn gemakkelijk te lezen, onderhouden en over te dragen, maar nemen meer ruimte in en bieden minimale beveiliging.
Binaire bestanden
Binaire bestanden (vaak .bin) slaan data op als raw bytes (0'en en 1'en). Ze zijn compact, niet menselijk leesbaar, en bieden betere dataintegriteit en beveiliging.
Kern bestandsoperaties
Ongeacht type, draait C bestandsbehandeling om vier operaties:
- Een nieuw bestand aanmaken
- Een bestaand bestand openen
- Een bestand sluiten
- Uit een bestand lezen of ernaar schrijven
Een bestandspointer voorbereiden
Alle bestandsoperaties vereisen een FILE * pointer om het open bestand te refereren:
FILE *fptr;
Bestanden openen: aanmaken en bewerken
stdio.h) opent een bestand en retourneert een FILE * pointer. De syntaxis is:
fptr = fopen("bestandsnaam", "modus");
Voorbeeldgebruik:
fopen("E:\\cprogram\\newprogram.txt", "w");
fopen("E:\\cprogram\\oldprogram.bin", "rb");
Uitleg:
newprogram.txtwordt aangemaakt (indien afwezig) en geopend voor schrijven in modus'w', wat bestaande inhoud overschrijft.oldprogram.binwordt geopend voor binaire lezen in modus'rb'; schrijfpogingen zullen falen.
| Modus | Betekenis | Gedrag als bestand ontbreekt |
|---|---|---|
r | Openen voor lezen | Retourneert NULL |
rb | Openen voor binaire lezen | Retourneert NULL |
w | Openen voor schrijven (overschrijven) | Maakt bestand aan indien afwezig |
wb | Openen voor binaire schrijven (overschrijven) | Maakt bestand aan indien afwezig |
a | Openen voor toevoegen | Maakt bestand aan indien afwezig |
ab | Openen voor binaire toevoegen | Maakt bestand aan indien afwezig |
r+ | Lezen en schrijven | Retourneert NULL |
rb+ | Lezen en schrijven in binaire modus | Retourneert NULL |
w+ | Lezen en schrijven (overschrijven) | Maakt bestand aan indien afwezig |
wb+ | Lezen en schrijven in binaire modus (overschrijven) | Maakt bestand aan indien afwezig |
a+ | Lezen en toevoegen | Maakt bestand aan indien afwezig |
ab+ | Lezen en binaire toevoegen | Maakt bestand aan indien afwezig |
Een bestand sluiten
Na alle I/O operaties, sluit het bestand altijd met fclose() om bronnen vrij te geven en buffers te flushen:
fclose(fptr);
Tekstbestand I/O
Tekstbestanden worden behandeld met fprintf() en fscanf(), de bestand-gebaseerde tegenhangers van printf() en scanf(). Ze vereisen een FILE * pointer als eerste argument.
Voorbeeld 1: Schrijven naar een tekstbestand
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
// Pas het pad aan voor je OS
fptr = fopen("C:\\program.txt", "w");
if (fptr == NULL) {
printf("Fout bij openen bestand\n");
exit(EXIT_FAILURE);
}
printf("Voer een getal in: ");
scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
return 0;
}
Dit programma vangt een integer van de gebruiker en schrijft het naar program.txt.
Voorbeeld 2: Lezen uit een tekstbestand
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
fptr = fopen("C:\\program.txt", "r");
if (fptr == NULL) {
printf("Fout bij openen bestand\n");
exit(EXIT_FAILURE);
}
fscanf(fptr, "%d", &num);
printf("Gelezen waarde: %d\n", num);
fclose(fptr);
return 0;
}
Dit na het eerste voorbeeld uitgevoerd, toont het opgeslagen integer.
Extra hulpmiddelen zoals fgetc() en fputc() volgen hetzelfde patroon.
Binair bestand I/O
Binaire bestanden worden gemanipuleerd met fwrite() voor schrijven en fread() voor lezen. Beide functies accepteren vier argumenten: pointer naar data, grootte van elk element, aantal elementen, en FILE * pointer.
Schrijven naar een binair bestand
fwrite(adresData, grootteData, aantalData, filePointer);
Voorbeeld 3: Schrijven naar een binair bestand met 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("Fout bij openen bestand\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;
}
Lezen uit een binair bestand
De overeenkomstige fread() signature spiegelt fwrite():
fread(adresData, grootteData, aantalData, filePointer);
Voorbeeld 4: Lezen uit een binair bestand met 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("Fout bij openen bestand\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;
}
Dit programma reproduceert de data geschreven in Voorbeeld 3.
Willekeurige toegang met fseek()
Wanneer een bestand veel records bevat, kan het sequentieel doorlopen naar een specifieke entry inefficiënt zijn. fseek() verplaatst de bestandspointer naar een willekeurige positie, wat directe toegang mogelijk maakt.
Syntaxis
fseek(FILE *stream, long int offset, int whence);
stream: pointer geretourneerd doorfopen().offset: aantal bytes om te verplaatsen.whence: startpunt –SEEK_SET,SEEK_CUR, ofSEEK_END.
| Constante | Betekenis |
|---|---|
SEEK_SET | Offset begint vanaf het begin van het bestand. |
SEEK_CUR | Offset begint vanaf de huidige cursorpositie. |
SEEK_END | Offset begint vanaf het einde van het bestand. |
Voorbeeld 5: Omgekeerde-volgorde lezen met 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("Fout bij openen bestand\n");
exit(EXIT_FAILURE);
}
// Ga naar het laatste record
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);
// Stap twee records terug (huidige + één meer) om de vorige entry te lezen
fseek(fptr, -2 * sizeof(struct threeNum), SEEK_CUR);
}
fclose(fptr);
return 0;
}
Dit fragment demonstreert hoe je een binair bestand in omgekeerde volgorde doorloopt, beginnend bij het laatste record.
C Taal
- STL-bestanden begrijpen: De ruggengraat van 3D-printen
- Bestands-I/O in C: Bestanden aanmaken, openen, lezen en schrijven
- C Header-bestanden begrijpen: Typen, gebruik en best practices
- Foutafhandeling in C: Best Practices & Technieken
- File I/O in C++ Beheersen: Lezen en Schrijven met fstream
- C++ Signaalverwerking onder de knie: Veilige interruptafhandeling en schone programmaterminatie
- C# Exception Handling Beheersen: Strategieën & Best Practices
- C# Bestands-I/O Beheersen: Lezen, Schrijven en Streams Beheren
- Verilog File I/O onder de knie: Openen, Lezen, Schrijven en Sluiten
- Python Bestands I/O: In- en uitvoerbewerkingen onder de knie krijgen
- Java-bestandsbewerkingen onder de knie krijgen met java.io – Aanmaken, lezen, schrijven en verwijderen