Programozás II. Fájlkezelés Kocsis Zoltán Tamás 2013. 03. 28
Fájlkezelés
Az stdio.h-ban megadott FILE* típusú pointerrel és függvényekkel lehet elérni a fájlunkat. FILE *fp; /* fájl mutató (file pointer/handle) */ fp= fopen("szoveg.txt", "wt"); /* megnyitás */ if (fp==NULL) { printf("Nem sikerült megnyitni!"); ……… } else { fprintf(fp, "Hello, vilag!\n"); for (i=0; i<20; ++i) fprintf(fp, "%d\n", i); fclose(fp); /* bezárás */ }
Fájlkezelés (folyt.)
Megnyitás módja: írás (w) v. olvasás (r), szöveges (t) v. bináris (b). Az fopen() visszatérési értéke: hivatkozás a nyitott fájlra. Sikertelen megnyitásnál értéke: NULL pointer – ezt ellenőrizni kell.
Fájlkezelés (folyt.)
Windowson az elérési útban \ az elválasztó: C:\Windows\hatter.bmp, Unixon / van: /usr/bin/firefox. Az fopen() mindig elfogadja a /-t. Ha a \-hez ragaszkodunk, azt viszont \\-nek kell írni a sztring belsejében, mivel a \ önmagában a speciális karaktereket jelöli (pl. \n). Létezik még két további megnyitás mód is: hozzáfűzés (a). Ilyenkor a fájlt írásra nyitjuk meg, de a meglévő tartalmát meghagyva. Az írás mutató a fájl végére mutat, vagyis a meglévő tartalomhoz hozzáadva lehet folytatni az írást. írás-olvasás (+). Ilyenkor írni és olvasni is lehet. Más betűkkel együtt használjuk: pl. r+ azt jelenti, hogy a fájl tartalma megmarad, de írni is lehet bele
Fájlkezelés (folyt.)
A szövegfájlokat a printf() és a scanf() párjával, az fprintf()-fel és az fscanf()-fel lehet kezelni. Ezeknek első paramétere a megnyitott fájl, a folytatás pedig ugyanúgy van, mint a képernyő / billentyűzet párjuknál. A szövegfájlokat lineárisan kezeljük, nem ugrunk benne ide-oda.
Fájlkezelés (folyt.) Szövegfájlok szerkezete
Egyes rendszerek máshogy jelzik a szövegfájlokban a sorok végét (\n). Windowson két bájt, CR LF (0x0D 0x0A), Unixokon csak LF (0x0A).
Fájlkezelés (folyt.) Szövegfájlok szerkezete
Szöveges módban nyitott fájlnál ezt megoldja helyettünk a C. Kezelés: fp=fopen(név, "…t"), fprintf(fp, …), fscanf(fp, …).
Fájlkezelés (folyt.) Szövegfájlok szerkezete
A "t"-vel, szöveges módban megnyitott fájl olvasásakor és írásakor a konverziót a C fájlkezelő függvényei automatikusan elvégzik. Vagyis Unixon pl. a \n sortörést változatlanul kiírják a fájlba, Windowson viszont a printf("\n") hatására nem egy, hanem két bájt kerül a fájlba. Viszont az automatikus konverzió miatt ezzel nekünk nem kell foglalkozni, csak annyiban, hogy "t" módban kell megnyitni a fájlt, ha szöveges formátumot szeretnénk. A fenti apróságtól eltekintve a szövegfájlok sokkal inkább hordozhatóak, hiszen a bennük tárolt adatok nem függenek a számábrázolás módjától, amit az adott géptípus hardvere határoz meg. Ez az oka annak, hogy az utóbbi években egyre inkább terjednek a szöveg alapú formátumok: szöveges dokumentumok: HTML, RTF, XML (DOCX) adatok, adatbázisok: XML
Fájlkezelés (folyt.) Bináris fájlok szerkezete
struct adat { char nev[13]; short eletkor; } tomb[2]; strcpy(tomb[0].nev, "Ernoke"); tomb[0].eletkor=4; strcpy(tomb[1].nev, "Szultan"); tomb[1].eletkor=5; FILE *fp; fp=fopen("adat.dat", "wb"); /* write, binary */ fwrite(tomb, sizeof(struct adat), 2, fp); fclose(fp);
Fájlkezelés (folyt.) Bináris fájlok szerkezete
fread(ptr, méret, db, fp), fwrite(ptr, méret, db, fp). A ptr által mutatott memóriaterület olvasása/írása az fp fájlból/fájlba. Az adat méret bájt méretű, db darabszámú elemekből áll. Visszatérési érték a sikeresen olvasott/írt elemek száma. Itt akad egy pár újdonság. Első a void* típusú mutató (az fwrite() és az fread() első paramétere ilyen típusú). Ez a pointertípus azt jelenti, hogy nincsen meghatározva, milyen típusú elemre mutat az a pointer, hanem csak annyi, hogy valahova a memóriába mutat. Az fread() és fwrite() függvények azért várnak ilyen típusú mutatót, mivel nem foglalkoznak az általunk megadott adatok értelmével – egyszerűen csak elvégzik a fájlműveletet.
Fájlkezelés (folyt.) Bináris fájlok szerkezete
Egy valamit azért mégis tudniuk kell az adatunkról, mégpedig azt, hogy hány bájtból áll. Ezt a fordító meg tudja mondani: a sizeof(típus) kifejezés megadja azt, hogy hány bájtból áll a megadott típus. Ez kényelmes, egyrészt mivel nekünk nem kell fejben tartani, másrészt a fordító úgyis jobban tudja. Ha átvisszük egy másik géptípusra a programunkat, ott a sizeof(típus) értéke más lehet. Az fread() és fwrite() második paramétere a típus méretét adja meg, a harmadik paraméter pedig a darabszámot. Ez a megoldás tömbök kezelésére kiválóan alkalmas: előbb egy tömbelem mérete, utána a tömb elemszáma.
Fájlkezelés (folyt.) Bináris fájlok szerkezete
Az fwrite() visszatérési értéke azt mutatja, hány elemet sikerült kiírnia, az fread()-é pedig azt, hányat olvasott be. Ezek is „méret”, vagyis size_t típusúak. (A size_t típus egy egész szám, azonban a mérete (bitszáma) eltérhet az integerétől.) A fájl tartalma: 45 72 6E 6F 6B 65 00 21 80 07 40 00 7B 26 04 00 Ernoke.!..@.{&.. !..@.{ 53 7A 75 6C 74 61 6E 00 F0 05 59 2A 6A 22 05 00 Szultan...Y*j".. Bináris fájlok kezelése: fp=fopen(név, "…b"), fread(…), fwrite(…).
Fájlkezelés (folyt.) Bináris fájlok szerkezete
Érdekesség. A fenti sztringet 13 karakteren tároljuk, de a beírt sztring rövidebb. A fennmaradó helyen memóriaszemét van – ezt a színezett rész mutatja. Erről volt szó a sztringek kapcsán. Külön érdekesség még, hogy van egy extra bájt is a struktúrában, a sztring mintha 14 karaktert foglalna. Ez már nem tartozik a sztringhez, hanem egy ún. kitöltő (padding) bájt. Ezt a fordító a sztring és a short közé tette, valószínűleg azért, mert a processzor igényelte azt, hogy a short párosadik bájton kezdődjön. Ha binárisan írjuk ki fájlba az adatokat, ez is látszik. Az is megfigyelhető, hogy ezen a gépen a kétbájtos short típus helyiértékei fordított sorrendben vannak. Előbb az alsó helyiérték: 4, utána a felső: 0. Ernőke életkora 4+0*256 év. Ez is az adott számítógéptípus tulajdonságaitól függ, és egy olyan dolog, amely miatt nem hordozhatóak egyik gépről másikra az ilyen gondolkodás nélkül, memóriatartalmat egy az egyben kiírt bináris fájlok.
Feladat
Készítsen programot, mely eldönti az indító parancssorban megadott azonosítójú fájlról, hogy ASCII kódú szövegfájl-e, vagy bináris fájl-e! Ha parancssori paraméter nélkül futtatják a programot, akkor ismertesse a képernyőn a használatát!
Feladat
Készítsen programot, mely az indító parancssorban megadott szövegfájlokat egyesíti a megadás sorrendjében a parancssorban utolsóként előírt azonosítójú szövegfájlba! Ha parancssori paraméter nélkül indítják a programot, akkor ismertesse a képernyőn, hogyan kell használni! Ha csak egy fájlazonosító van a parancssorban, akkor a szabvány bemenet másolandó bele. A fájlok egyesítése során a folyamat előrehaladásáról tájékoztatni kell a képernyőn! A szabvány bemenet másolása esetén végül közlendő az eredményfájl mérete!