Szöveges / bináris módban megnyitott fájlok
fopen
|
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
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
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.
Hozzunk létre egy sztringet az alábbi módon:
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:
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 notepad
del. 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
Írjuk ki ugyanezt a sztringet bináris fájlba az alábbi módon:
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 különbség tehát összefoglalva:
0x41
, 0x0A
, 0x42
)'A'
, újsor
, 'B'
). És ha bizonyos karaktereket a C program másként ábrázol, mint az operációs rendszer szöveges fájljai, akkor automatikusan megtörténik az ábrázoláskonverzió.A szabály olvasásra analóg formában igaz:
0x0D
bájtját.Pusztán érdekességként nézzük az alábbi kevert verziókat:
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:
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.
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 notepad
del 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