Fájlkezelés C++ alatt 2009. 11. 20 – péntek Jordán Sándor
Plang alatt már találkoztunk a fájlkezelés rejtelmes világával Plang alatt már találkoztunk a fájlkezelés rejtelmes világával. Ott megvolt az a biztonság, hogy ha valamit elbaltáztunk, akkor nem történik nagyobb hiba, mert a program futási limiterrel volt ellátva, valamint a fájlokat is csak szimulálta, nem volt tényleges írás a merevlemezre.
C++ alatt viszont már élesben mennek a dolgok C++ alatt viszont már élesben mennek a dolgok. Ha valaki végtelen ciklust ír … akkor végtelen ciklus is lesz belőle (néha jól jön egyébként). Valamint itt valóságos fájlhasználatról van szó … ha a végtelen ciklust ötvözzük egy fájlba való kiírással, akkor könnyen nyerhetünk egy teli merevlemezt … azt meg kevésbé tolerálják az oprendszerek
Előfordulhat mindenkivel, hogy elsőre valami előre nem látott hiba történik és ekkor bizony elveszhet az adott fájl tartalma. Jó tanács: amíg tesztelési fázisban vagyunk, addig csak az eredeti fájl egy másolatával dolgozzunk, mert az kellemetlen, ha több órás gépelést egyetlen gombnyomással semmissé tudunk tenni.
Kétféle fájl létezik:. - Bementi fájl Kétféle fájl létezik: - Bementi fájl - Kimeneti fájl Egyszerre nem lehet mindkettő egy fájl … legalábbis C++ alatt nem. De semmi gond, ha kell akkor a megnyitott bemeneti fájlt bezárhatjuk és újra nyithatjuk kimeneti fájlként.
A konzolra való kiíratáshoz az <iostream> nevű fájlt „inklúdolni” (include) kellett a használat előtt … utána képesek voltunk kiíratni a konzolra és adatokat bekérni a konzolról. Annyit még meg kellett tennünk, hogy eláruljuk a gépnek, hogy a használni kívánt parancsok melyik névtérben (namespace) helyezkednek el. Ez volt az std.
Ha belegondolunk, akkor a fájlkezelésnél sincs semmi újdonság Ha belegondolunk, akkor a fájlkezelésnél sincs semmi újdonság. Fájlba szeretnénk írni és fájlból szeretnénk olvasni. Ehhez is kell egy fájl amit inkludálnunk kell a program elején. Ez lesz az <fstream> … f mint file. Valamint egy névteret is meg kell jelölnünk neki, ám ez ebben az esetben is az std lesz.
Tehát amikor fájlokkal szeretnénk dolgozni, akkor az alábbi sorokról nem feledkezhetünk el: #include <fstream> using namespace std;
Lesz nekünk két új fájltípusunk:. - ifstream -> if mint „in file” Lesz nekünk két új fájltípusunk: - ifstream -> if mint „in file” - ofstream -> of mint „out file” Példa a deklarációra: ifstream be_fajl; ofstream ki_fajl;
Ezzel még nem nyitottunk meg semmilyen fájlt sem, csak deklaráltunk hozzá változókat. Tehát a logikai fájlokat most össze kellene kötni valamilyen tetszőleges fizikai fájlokkal. Ennek két féle módja is van:
I. Ifstream be_fajl;. befajl. open(„Bemenet I. Ifstream be_fajl; befajl.open(„Bemenet.txt”); Innentől a be_fajl a Bemenet.txt-be fog dolgozni. II. Ifstream be_fajl(„Bemenet.txt”); Ez egy gyorsabb és kompaktabb megnyitás
Az előző kódok csak akkor működnek helyesen ha a Bemenet Az előző kódok csak akkor működnek helyesen ha a Bemenet.txt az adott mappában van. Ha nincs ott és mégis használni szeretnénk akkor elérési út beírásának segítségével is hivatkozhatunk a fájlra. befajl.open(„c:\dokumentumok\bement.txt”); (windows alatt) befajl.open(„/home/dokumentumok/bem.txt”); (unix alapú rendszer alatt)
A felhasználóbarát programkészítéshez hozzá tartozik az is, hogy tetszőleges nevű fájlba íratjuk ki a felhasználó adatait, amit tőle kérünk be. DE előtte kell egy kis átalakítást végeznünk a bekért adaton!!!
Pl: string program_neve; cin >> program_neve; Ezzel bekértük a fájl nevét, de van egy rossz hírem … fájlnévként a program nem stringet vár hanem karakter tömböt!! De nem nagy a baj … át tudjuk alakítani karakter tömbbé a string változónkat.
A string típusban található egy függvény amely karaktertömbbé alakítja át a szöveg típusú változót. Ez így fest: program_neve.c_str(); Ezt már bátran írhatjuk a megnyitandó fájl neve helyére
Tehát akkor kompletten így festene egy a felhasználótól bekért fájlnevű fájl megnyitása: string fajl_neve; cin >> fajl_neve; ifstream be_falj; be_fajl.open(fajl_neve.c_str());
Csak hogy itt megint problémába ütközünk … mert mi van ha a „vicces” felhasználó (Mosoly Misi ) olyan fájlnevet ad meg nekünk ami nem is létezik … akkor jót röhöghet rajtunk, hogy hogy elhasalt a programunk az ő kis tréfáján … Vagy jól felkészülünk a poénjára és az nevet igazán aki utoljára nevet stílusban játszunk
A trükk ott van az egészben, hogy mi szépen leellenőrizzük sutyiban, hogy létezik-e a fájl … és ha nem akkor tudatjuk vele és/vagy bekérjük az új fájlnevet. Azt, hogy sikerült-e megnyitni a fájl például így kérdezhetjük le: Ifstream be_fajl(„Bemenet.txt”); if(be_fajl.fail()) cout << „Programozó VS Mosoly Misi -> 1:0”;
Sőt … hogy mi nevethessünk igazán ezt egy olyan ciklusba tehetjük, ami addig nem engedi tovább lépni a programot ameddig nem ad jó fájlnevet a felhasználó. while(be_fajl.fail()){ be_fajl.clear() // szükséges az újra inicializáláshoz cin >> fajl_neve; be_fajl.open(fajl_neve.c_str()); }
A fájlt használat után be kell zárni A fájlt használat után be kell zárni!! A program végén úgy is megtörténne, de addig megnyitva maradna a fájl, ami nekünk nem jó … mindennek rend a lelke! A bezárás így fest: be_fajl.close(); Ezután be_fajl néven nyithatunk is akár egy új fájlt FIGYELEM … FÁJL ÚJRA MEGYNITÁSA ÍRÁSRA ADATVESZTÉST OKOZ
Egy fájlal való munka kísértetiesen hasonlít a konzolon való munkához … ugyan úgy kell bele kiíratni (<<) és beolvasni (>>) csak itt a cin és cout kifejezések helyett agy kimeneti fájl neve illetve bementi fájl neve kell. Például: be_fajl >> adat; fájlból való olvasás ki_fajl << adat; fájlba való írás
A bementi fájlokból általában az összes adatot ki szeretnénk olvasni … de nem tudjuk előre, hogy mennyi van belőlük … de láttuk a Plangos pályafutásunk alatt, hogy van egy olyan dolog, amit a fájl végének nevezünk, ameddig mindig tudunk olvasni. Angolul: end of file EOF Tehát addig kell olvasnunk, ameddig nem találjuk meg az eof jelet!
Nézzünk egy példát az összes elem kiolvasására: while(. be_fajl Nézzünk egy példát az összes elem kiolvasására: while(!be_fajl.eof()){ be_fajl >> data; } Tehát ameddig nem találja meg a program a fájl vége jelet, addig olvassa ki belőle az adatokat szépen.
Van még egy eszköz, ami a segítségünkre van a fájlkezeléshez Van még egy eszköz, ami a segítségünkre van a fájlkezeléshez. Előfordulhat, hogy az az igény ötlik fel bennünk, hogy egy egész sort kell beolvasnunk attól függetlenül, hogy milyen típusú adatok vannak abban a sorban. Az erre szolgáló eszköz a getline.
Ennek két változata van:. I. Az egész sor beolvasása. II Ennek két változata van: I. Az egész sor beolvasása II. Az egész sor beolvasása adott karakterig I. Getline(be_fajl, a, ‘;’); Beolvasás a be_fajl-ból az „a” valtozóba egészen addig amíg nem találja meg az első „;”-t II. Getline(be_fajl, a); A komplett sor beolvasása a be_fajl-ból az ”a” valtozóba
Most már tudunk annyit a szövegkezelésről, hogy bátran neki is vághatunk az első programunknak: Feladat: kérjünk be a felhasználótól egy fájlnevet és nyissuk meg, majd olvassuk ki belőle egyenként a szám adatokat és írassuk ki egy másik fájlba;
#include <iostream> #include <fstream> using namespace std; int main(){ ifstream bf; string nev; cout << "Kerem a beolvasando fajl nevet!" << endl; cin >> nev; bf.open(nev.c_str()); while(bf.fail()){ cout << "Hibás fajl nev" << endl; cout << "Kerem a helyes fajlneve!" << endl; cin >> nev; bf.clear(); bf.open(nev.c_str()); }
string adat; ofstream kf; kf. open("uj_adatok string adat; ofstream kf; kf.open("uj_adatok.txt"); bf >> adat; // Előreolvasás!!! while(!bf.eof()){ bf >> adat; kf << adat << endl; } bf.close(); kf.close(); cout << endl << "Adatok atmasolasa kesz." << endl; return 0; }