A C nyelv fájlkezelése is stream orientált, de a nyelv korlátaiból adódóan nincs stream objektumunk. Helyette egy FILE típusú mutatónk van, amivel függvények segítségével tudunk műveleteket végezni. Fájlkezelésnél itt is megkülönböztetünk szöveges és bináris fájlkezelést. Kezdésnek nézzünk egy példa programot, ami a saját forráskódját kiírja:
#include <stdio.h>
int main()
{
FILE *source = fopen("fileRead.c", "r");
if (source == NULL)
{
printf("Hiba a fileRead.c megnyitasa kozben");
return 1;
}
char sor[90];
while (feof(source) == 0)
{
fgets(sor, sizeof(sor)/sizeof(char), source);
printf("%s", sor);
}
fclose(source);
return 0;
}
Az első fontos függvény, amivel találkozunk, az az fopen. Ez nyitja meg a fájlt és visszatérési értéke egy FILE pointer. Az fopen első paramétere a fájl neve, amit meg szeretnénk nyitni, a második szöveges paramétere pedig a megnyitás módja. Ez az alábbi értékeket veheti fel:
| Mód | Jelentés |
|---|---|
r |
Fájl megnyitása olvasásra. A fájlnak léteznie kell |
w |
Fájl megnyitása írásra. Felülír vagy létrehoz. |
a |
Fájl megnyitása írásra hozzáfűzéssel. |
r+ |
Fájl megnyitása olvasásra és hozzáfűzésre. A fájlnak léteznie kell. |
w+ |
Fájl megnyitása írásra és olvasásra |
a+ |
Fájl megnyitása olvasásra és hozzáfűzésre. |
Bináris módon való kezeléskor a b karaktert hozzá kell fűzni a megnyitás módjához. Például ha olvasásra szeretnénk megnyitni a foo.bin fájlt, akkor az rb módot kell megadnunk. Az fopen függvénynek is létezik egy biztonságosabb változata, ami az fopen_s nevet kapta. Ez több hibaeshetőségre fel van készítve és egy errno_t hibakódot ad vissza, ha hibába ütközik. Az fopen_s függvényről a https://en.cppreference.com/w/c/io/fopen címen, a hibakódokról pedig a https://learn.microsoft.com/en-us/cpp/c-runtime-library/errno-constants?view=msvc-170 címen lehet olvasni.
Az feof függvénnyel tudjuk ellenőrizni, hogy a fájl végén vagyunk-e már vagy sem. Ez 0 értéket ad vissza, ha még nem. Az fgets függvénnyel tudjuk egy sorát beolvasni a fájlnak. Első paraméternek egy buffernek kell lennie, a második paraméter a maximálisan beolvasható karakterek száma, a harmadik paramétere pedig a fájl pointer.
A fájlkezelés végén az fclose függvény hívásával le kell zárnunk a fájlt és felszabadítani a hozzá tartozó mutatót.
Az fscanf és fprintf hívásokkal formázottan tudunk adatot írni és olvasni fájlokból. Ezek ugyanúgy működnek, mint a konzolra író és olvasó változatok. Paraméterezésben annyi eltérés van, hogy az első paraméternek a fájl mutatónak kell lennie.
/*Egész olvasása a file-ból*/
fscanf(file, "%d", &egesz);
/*Egy egész szám írása a fájlba*/
fprintf(file, "%d", egesz);
Pozicionálni a fájlban az fseek függvény segítségével tudunk. Ennek a függvénynek is az első paramétere a fájl mutató. A második paraméter a pozíció offset hosszú egész (long) formában. A harmadik paraméter pedig a referencia pontot határozza meg, hogy honnan pozicionálunk. Ez három konstans közül egy lehet:
SEEK_SET– A fájl elejétől pozícionálSEEK_END– A fájl végétől pozícionálSEEK_CUR– A jelenlegi pozíciótól pozícionál.
Az aktuális pozíció az ftell hívással kérdezhető le, aminek paraméterül egy fájl mutatót kell adnunk. A függvény visszatérési értéke pedig az aktuális pozíció.
Bináris kezelés
Bináris fájlkezelés esetén a két fontos függvény, amivel dolgozni fogunk az fwrite és az fread. Az fwrite segítségével tudunk bináris módon fájlt írni. Ennek első paramétere egy mutató a kiírandó adatra, a második paramétere a kiírandó adat mennyiség, a harmadik paramétere pedig, hogy hány alkalommal szeretnénk az adott adatot kiírni. A negyedik és egyben utolsó paramétere pedig maga a fájl mutató.
Az fread paramétezése ugyanez, annyi különbséggel, hogy az első paraméter egy mutató, amibe az adat kerülni fog, a harmadik paraméter pedig, hogy mennyiszer szeretnénk beolvasni a korábban meghatározott méretet.
#include <stdio.h>
#include <string.h>
typedef struct
{
char neve[50];
int jegy;
} tanulo_t;
int main()
{
tanulo_t tanulo;
tanulo.jegy = 5;
strncpy(tanulo.neve, "Gipsz Jakab", 11);
FILE *binaryFile = fopen("tanulo.bin", "wb");
fwrite(&tanulo, sizeof(tanulo), 1, binaryFile);
fclose(binaryFile);
tanulo_t beolvasott;
FILE *visszaolvasott = fopen("tanulo.bin", "rb");
fread(&beolvasott, sizeof(tanulo), 1, visszaolvasott);
fclose(visszaolvasott);
printf("%s - %d\r\n", beolvasott.neve, beolvasott.jegy);
return 0;
}
A fenti példában egy példányt olvasunk és írunk ki a tanulo_t struktúrából. Ha például egy 50 elemű tömböt szeretnénk ebből a típusból kiírni vagy beolvasni, akkor a sizeof(tanulo) után 50-et kellett volna megadni.