Szöveges / bináris módban megnyitott fájlok
fopen
Szövegesen / binárisan megnyitott fájlok

Tartalomjegyzék

Bevezetés

Az ASCII_art demóban binárisan megnyitott fájlból olvastunk az fscanf függvénnyel szöveget, majd az fread függvénnyel bájtokat. Ennek kapcsán azt nézzük meg kicsit jobban, hogy mit is jelent a szöveges és bináris módban megnyitott fájl.

Először is: természetesen minden fájl bináris, adott számú bájtot tartalmaz. Az, hogy egy fájl szöveges vagy nem, lényegében pusztán értelmezés kérdése. Ha pl. egy két bájt méretű fájl tartalma

0x41 0x42

akkor az a fájl tartalmazhatja az 'AB' szöveget, hiszen a 0x41 az 'A' karakter ASCII kódja, a 0x42 pedig a 'B'-é. Ekkor az

char c[2];
fscanf(fp, "%c%c", &c[0], &c[1]);

pontosan az 'A' és 'B' karaktereket olvassa be c[0]-ba és c[1]-be. Illetve c[0]-ba a 0x41-et, c[1]-be a 0x42-t. Másrészt a fájl tartalmát értelmezhetjük egyetlen 16 bites előjel nélküli egészként is, melynek értéke 0x4142 = 16706. Ekkor a

short unsigned int a;
fread(&a, 2, 1, fp);

függvényhívás ezt a 0x4142 számértéket olvassa be a-ba.

Mindkét esetben ugyanaz történt: A két bájt bekerült a fájlból a C program memóriájába. Az A és B karakterek, illetve a 16706 számérték csupán értelmezés kérdése.

Ha viszont minden csak értelmezés kérdése, akkor felmerül a kérdés:

Nem feltétlenül.

Egy egyszerű példa

Megjegyzés
Az alábbi példa csak Windowson látványos.

Hozzunk létre egy sztringet az alábbi módon:

char str[] = "A\nB";

A sztring 3+1 karaktert tartalmaz, melyek jelölése és C programbeli belső ábrázolása az alábbiak

'A'   '\n'  'B'  '\0'
0x41  0x0A  0x42 0x00

Hozzunk létre egy szöveges fájlt, és írjuk bele a sztringet fprintf függvénnyel:

FILE *fp = fopen("fajl.xx", "wt");
fprintf(fp, "%s", str);
fclose(fp);

Természetesen azt várjuk, hogy a fájlba három karakter kerül be, az A, az újsor és a B. Ez így is van. Meggyőződhetünk róla, ha megnyitjuk a fájlt notepaddel. Ha viszont megnézzük a fájl méretét, akkor négy bájtot látunk. Ennek oka az, hogy a Windows szöveges fájljai az újsor karaktert két bájttal (0x0D, 0x0A) ábrázolják. Fájlunk belső ábrázolása az alábbi négy bájt lesz:

'A'  újsor     'B'
0x41 0x0D 0x0A 0x42
Megjegyzés
Ez rögtön azt is mutatja, hogy a szöveges fájl bájtokban mért mérete nem feltétlenül adja meg a benne tárolt karakterek számát, annál nagyobb is lehet.

Írjuk ki ugyanezt a sztringet bináris fájlba az alábbi módon:

FILE *fp = fopen("fajl.xx", "wb");
fwrite(str, 1, 3, fp);
fclose(fp);

Az fwrite függvénynek megadtuk, hogy három darab, egyenként egy bájt méretű adatot másoljon az str tömb elejétől az fp fájlba. A fájl most három bájtos lett, pontosan ugyanazt a három bájtot tartalmazza, mint az str sztring eleje:

0x41 0x0A 0x42

Ha a bináris módban elkészült fájlt szövegként megnyitjuk a notepad programmal, akkor nem is fogjuk látni a soremelést, mert a fájl nem (illetve hiányosan) tartalmazza az újsor karaktert.

A szabály

A különbség tehát összefoglalva:

A szabály olvasásra analóg formában igaz:

Kin múlik

Pusztán érdekességként nézzük az alábbi kevert verziókat:

FILE *fp = fopen("fajl.xx", "wt");
fwrite(str, 1, 3, fp);
fclose(fp);

A fájlt szöveges módban nyitjuk meg, és az fwrite függvénnyel írunk bele 3 bájtot. Mert megtehetjük. Meglepetés: a fájl négy bájtos lesz, megtörténik a 0x0A -> 0x0D 0x0A konverzió.

Másik példa:

FILE *fp = fopen("fajl.xx", "wb");
fprintf(fp, "%s", str);
fclose(fp);

A fájlt bináris módban nyitjuk meg, és fprintf függvénnyel írunk bele szöveget. Meglepetés: a fájl három bájtos lesz, nem történik meg a konverzió.

Vagyis nem az író-olvasó függvényeken múlik, hanem a fájlnyitás módján.

Hordozhatóság

Mindezek az érdekességek Windowson tapasztalhatóak, Unixon például nem. A Unix (Linux, OS X) szöveges fájlok ugyanis az újsor karaktert ugyanazzal az egy 0x0A bájttal ábrázolják, mint a C program. A konverziós szabály a bájtokról és karakterekről persze ott is igaz, csak a konverzió észrevehetetlen.

Ez egyrész Unixon kényelmes, mert tökmindegy, hogy a fájlt milyen módban nyitjuk meg. Másrészt rögtön látszik az a probléma, hogy a szöveges fájlok nem hordozhatóak operációs rendszerek között. Egy Unixon megírt szöveges fájlt Windowson notepaddel megnyitva, nem látjuk benne a soremeléseket.

Természetesen nagyon könnyű olyan konvertereket írni (házi feladat), melyek beírják a 0x0D-ket minden 0x0A bájt elé egy unixos szöveges fájlban, vagy kiveszik a 0x0D-ket a windowsos fájlokból; de a konverzióra figyelnünk kell.

Különböző operációs rendszerek újsor-reprezentációiról bővebben itt