Curs 13
-
Upload
lungu-madalin -
Category
Documents
-
view
3 -
download
1
description
Transcript of Curs 13
1
În practică, programele lucrează cu un volum mare de date. Stocarea datelor se
face pe diverse suporturi magnetice (hard – disc, dischetă) sub formă de fişiere.
Se numeşte fişier o colecţie de date omogene (adică de acelaşi tip), stocate pe
suport extern şi accesată printr-un nume care reprezintă numele fişierului.
În C, un fişier poate fi orice, de la un fişier pe disc şi până la un terminal sau o
imprimantă. Un flux se poate socia unui anumit fişier executând o operaţie de deschidere.
Odată ce fişierul a fost deschis, poate avea loc transferul de informaţii între acest fişier şi
programul realizat.
Se lucrează cu două tipuri de fişiere, şi anume: text şi binare. Fişierele text sunt
fişierele în care datele sunt memorate sub forma unei succesiuni de caractere. Fiecare
caracter este memorat prin utilizarea codului ASCII pentru acel caracter.
Fişierele binare sunt fişiere organizate ca date binare (octeţii nu sunt consideraţi
ca fiind coduri de caractere). Acestea pot fi prelucrate folosind funcşiile fread şi
fwrite. În acest caz se consideră că înregistrarea este o colecţie de articole. Articolul
este o dată de un tip oarecare (predefinit sau definit de utilizator). La o citire, se transferă
într-o zonă specială, numită zonă tampon (buffer), un număr de articole care se
CURS
Prelucrarea fişierelor
13Sumar
Ierarhia de clase pentru lucrul cu fişiere Deschiderea fişierelor Închiderea fişierelor Intrări si ieşiri la nivel de fişier Accesul le datele dintr-un fişier Aplicaţii
2
presupune că au o lungime fixă. În mod analog, la scriere se transferă din yona tampon un
număr de articole de lungime fixă.
Ierarhia de clase pentru lucrul cu fişiere Pentru a putea efectua operaţii cu fişiere programele create trebuie să includă
fişierul de antet fstream.h.
La prelucrarea fişierelor se folosesc obiecte ale clasei filebuf care este o clasă derivată a
clasei streambuf. Obiectele clasei filebuf sunt utilizate de clase specifice pentru operaţii
cu fişiere şi care aparţin ierarhiei care are ca rădăcină clasa ios.
Clasa fstreambase este o clasă de bază pentru următoarele 3 clase:
ifstream - folosită la operaţii de intrare (citire);
ofstream - folosită la operaţii de ieşire (scriere);
fstream - folosită la operaţii de intrare/ieşire (citire/scriere).
Aceste 3 clase, au fiecare, încă o clasă de bază şi anume:
ifstream - derivă din clasa istream;
ofstream - derivă din clasa ostream;
fstream - derivă din clasa iostream.
streambuf ios
filebuf ostream istreamfstreambase
iostream
ofstreamfstreamifstream
3
De aici rezultă că pentru obiectele acestor clase se pot aplica funcţiile membru ale
claselor lor de bază, inclusiv supraîncărcarea operatorilor se inserare şi ştergere.
Deschiderea unui fişier
Prelucrarea unui fişier de pe disc începe cu deschiderea lui. În acest fel se poate
proceda în unul din următoarele moduri:
- se utilizează funcţia membru open cu un obiect al uneia din clasele ifstream,
ofstream sau fstream instanţiat fără parametri.
- Se utilizează parametri pentru deschiderea fişierului la instanţierea obiectelor.
În primul caz, obiectele se instanţiază folosind constructori impliciţi.
Fie, de exemplu, instanţierea:
ifstream obiect;
Obiectului obiect i se ataşează un fişier concret la apelul funcţiei open de forma:
obiect.open(…)
Funcţia open este definită în clasa fstreambase şi este supraîncărcată în clasele
derivate din aceasta. Ea are prototipul:
void open(char *fisier, int mod, int protectie)
Parametrul fişier este un pointer spre un şir de caractere care defineşte numele şi
extensia fişierului care se deschide, precum şi calea spre fişierul respectiv, dacă acesta nu
se află în directorul curent.
Parametrul mod defineşte modul de deschidere al fişierului. În acest scop se pot
folosii enumeratorii definiţi în clasa ios astefel:
in: - fişierul se deschide în intrare (citire);
out: - fişierul se deschide în ieşire (scriere);
ate: - după deschiderea fişierului, poziţia curentă în fişier este sfârşitul
4
fişierului; acest mod se foloseşte pentru a face căutări în fişier începând
cu
sfârşitul acestuia;
app: - deschidere pentru a adăuga înregistrări la sfârşitul fişierului;
trunc: - dacă fişierul există, conţinutul lui se pierde şi se creează un fişier nou;
el este incompatibil cu opţiunile ate şi app;
nocreate: - fişierul care se deschide cu această opţiune trebuie să existe; el nu se
deschide în creare;
noreplace: - dacă fişierul există şi este prezentă opţiunea out, atunci deschiderea este
admisă numai dacă se utilizează opţiunea ate sau app;
binary: - fişierul se deschide pentru a fi prelucrat binar; în mod implicit se
consideră că fişierele sunt prelucrate pe caractere (în mod text).
La o deschidere de fişier se pot folosi împreuna mai multe opţiuni, folosind
operatorul „|” (sau logic pe biţi).
Pentru obiectele clasei ifstream, opţiunea in este implicită, iar pentru cele ale
clasei ofstream, opţiunea out este implicită.
Parametrul protecţie defineşte modul de acces la fişier. În mod implicit acest
parametru are valoarea zero, şi aceasta înseamnă că fişierul respectiv nu are restricţii la
acces.
Rezultatul operaţiei de deschidere de fişier poate fi testat cu ajutorul cuvântului de
stare al streamului pentru care s-a apelat funcţia open.
Exemple:
1.ifstream fisier;
//se deschide fişierul fis.dat in citire
fisier.open(”fis.dat”,ios::nocreate);
5
//se testeaza starea obiectului fisier dupa deschidere
if(fisier)
{ //deschidere corecta
…
}
else
{ …
cout<<”eroare de dechidere \n”;
…
}
Opţiunea ios::in este implicită.
2. ofstream fis_iesire;
//se deschide fisierul factura.dat
fis_iesire.open(“factura.dat”);
if(!fis_iesire)
{ cout<<”eroare de deschidere” ;
…
}
3. ofstream fis;
//se deschide pentru adaugare fisierul binar stoc.dat
fis.open(”stoc.dat”, ios::app | ios::binary);
//se testeaza starea obiectului fis dupa deschidere
if(!fis)
{ …
cout<<”eroare la deschidere \n”;
…
6
}
else
{…
//deschidere corecta
…
}
Cea de a doua posibilitate de a deschide un fişier este aceea de a folosi parametrii
corespunzători la instanţierea obiectelor claselor ifstream, ofstream sau fstream. În acest
caz, constructorul apelat pentru instanţierea obiectului apelează în mod automat funcţia
open. Constructorii care deschid fişierele la instanţierea obiectelor claselor amintite mai
sus, au aceiaşi parametri ca şi funcţia open.
nume_clasa(char *fisier, int mod, int protectie)
unde:
nume_clasa - este ifstream, ofstream, sau fstream.
Parametrul protectie este şi în acest caz un parametru implicit, având valoarea
implicită egală cu zero.
Exemplele de mai sus pot fi rescrise astfel:
1. ifstream fisier(”fis.dat”,ios::nocreate);
if(fisier)
{ //deschidere corecta
…
}
else
{ …
cout<<”eroare de dechidere \n”;
…
7
}
2. ofstream fis_iesire(“factura.dat”);
if(!fis_iesire)
{ cout<<”eroare de deschidere” ;
…
}
3. ofstream fis(”stoc.dat”, ios::app | ios::binary);
//se testeaza starea obiectului fis dupa deschidere
if(!fis)
{ …
cout<<”eroare la deschidere \n”;
…
}
else
{…
//deschidere corecta
…
}
După deschiderea unui fişier, se pot face prelucrări asupra fişierului respectiv.
Închiderea unui fişier
După terminarea prelucrării unui fişier, în conformitate cu modul în care a fost
deschis, acesta trebuie închis. Închiderea unui fişier se realizează cu ajutorul funcţiei
close. Aceasta se apelează în mod obişnuit:
obiect.close();
sau
pobiec->close();
8
unde
obiect - este o instanţiere a uneia din clasele ifsteam, ofstream sau fstream.
În mod analog pobiect este un pointer spre unul din tipurile implementate prin
aceste clase.
Intrări, ieşiri în lucrul cu fişiere La prelucrarea fişierelor păstrate pe disc se pot folosi funcţiile membru ale
claselor istream, ostream sau iostream, acestea fiind clase de bază pentru clasele
specifice prelucrării fişierelor de pe disc. În particular, se pot folosi operatorii de inserare
şi extragere pentru operaţii de scriere cu format şi respectiv citire cu format dintr-un
fişier de pe disc.
Intrarea unui singur caracter se poate realiza cu ajutorul funcţiei membru get a
clasei istream. Ea are prototipul:
istream& get(char &);
Se obişnuieşte să se spună că funcţia get extrage un caracter din streamul curent
şi-l păstrează în zona de memorie referită de parametrul formal.
Funcţia get nu realizează avansul peste caracterele albe, deci ea extrage din
streamul curent caracterul, indiferent dacă acesta este un spaţiu alb sau nu.
Funcţia get are şi alte prototipuri care permit extragerea unui şir de caractere din
streamul curent şi anume:
istream& get(unsigned char *zona, int max, int term=’\n’);
istream& get(signed char *zona, int max, int term=’\n’);
Această funcţie extrage din streamul curent cel mult max-1 caractere sau până la
întâlnirea caracterului dat de valoarea lui term. Caracterele respective se păstrează în
zona de memorie spre care pointează zona.
9
După caracterele extrase din streamul curent se păstrează caracterul NUL (’\0’).
Terminatorul definit de term nu se păstrează în zona de memorie spre care pointează
zona.
Extragerea caracterului definit de term din streamul de intrare este posibilă cu
ajutorul funcţiei getline. Aceasta are prototipul similar cu funcţia get:
istream& getline(char *zona, int max, int term =’\n’);
Parametrii formali ai funcţiei getline au acelaşi sens ca şi în cazul funcţiei get.
Extragerea binară a datelor din streamul curent se realizează folosind funcţia read.
Aceasta are prototipul:
istream& read(unsigned char *zona, int n);
istream& read(signed char *zona, int n);
Funcţia extrage n octeţi din streamul curent şi îi transferă în zona de memorie spre
care pointează zona.
Ieşirea unui singur caracter se poate realiza cu ajutorul funcţiei put a clasei
ostream. Aceasta are prototipul:
ostream& put(char c);
Pentru a afişa n octeţi, se poate utiliza funcţia membru write a clasei ostream. Ea
are următoarele prototipuri:
ostream& write(const signed char *sir, int n);
ostream& write(const unsigned char *sir, int n);
10
Funcţia write afişează n caractere chiar dacă printre cei n octeţi spre care
pointează sir se întâlneşte caracterul NUL. Esenţa acestor funcţii este faptul că, asupra lor
biţi de format nu au nici un efect.
Accesul aleator la datele din fişier Accesul aleator se poate realiza folosind funcţii membru specifice ale claselor ofstream şi
ifstream.
Ptr. ofstream:
• long tellp() – returnează poziţie curentă
• seekp(…) – poziţionare pe o anumită poziţie în fişier
Ex.: fisier.seekp(n, beg(sau cur sau end)) unde n este deplasamentul în octeţi faţă de
început, curent, respectiv sfârşit.
Ptr. ifstream:
• long tellg() – returnează poziţie curentă
• seekg(…) – poziţionare pe o anumită poziţie în fişier
Ex.: fisier.seekg(n, beg(sau cur sau end)) unde n este deplasamentul în octeţi faţă de
început, curent, respectiv sfârşit.
Aplicaţii 1. Se citeste un fisier TEXT ce contine numere intregi despartite prin spatiu sau ENTER.
Sa se afiseze minimul si maximul din acel fisier. #include<iostream.h> #include<fstream.h> #include<values.h> void main() { ifstream f("d:\\LaboratorOOP\\numar.txt"); /* ifstream f; f.open("numar.txt"); */ if(!f) //sau f=NULL
11
{ cout<<"Eroare la deschiderea fisierului!"<<endl; return; } int x,max=-MAXINT,min=MAXINT; f.seekg(0,ios::beg); //ne pozitionam la inceputul fisierului while(!f.eof()) { f>>x; if (max<x) max=x; else if (min>x) min=x; } f.close(); cout<<"Maximul este: "<<max<<endl; cout<<"Minimul este: "<<min<<endl; }
2. Se citeste un fisier iext ce contine numere intregi despartite prin spatiu sau ENTER. Se
cere a se calcula si afisa pe ecran suma tuturor valorilor numerice din fisier si numarul de
elemente strict negative. #include<iostream.h> #include<fstream.h> void main() { ifstream f("numar.txt"); //sau: fstream f("numar.txt",ios::in); if(!f) //sau f=NULL { cout<<"Eroare la deschiderea fisierului!"<<endl; return; } int x[100], n_neg=0, s=0, i; f.seekg(0,ios::beg); //ne pozitionam la inceputul fisierului i=0; while(!f.eof()) { f>>x[i]; if(x[i]<0) n_neg++; s+=x[i++]; } f.close();
12
cout<<"Numarul elementelor negative: "<<n_neg<<endl; cout<<"Suma tuturor elementelor: "<<s<<endl; }
3. Se citeste un fisier TEXT ce contine numere intregi despartite prin spatiu sau ENTER.
Sa se afiseze minimul si maximul din acel fisier. Se va defini o clasa ptr numerele intregi
din fisier. #include<iostream.h> #include<fstream.h> #include<values.h> class numar { int n; public: int& retur(); friend istream& operator>>(istream&,numar&); }; int& numar::retur() { return n; } istream& operator>>(istream& a,numar& b) { a>>b.n; return a; } void main() { ifstream f("d:\\ LaboratorOOP\\numar.txt "); if(!f) { cout<<"Eroare la deschiderea fisierului!"<<endl; return; } numar x; int max=-MAXINT; int min=MAXINT; f.seekg(0,ios::beg); while(!f.eof()) { f>>x; if (max<x.retur()) max=x.retur(); else if (min>x.retur()) min=x.retur(); } cout<<"Minimul este: "<<min<<endl;
13
cout<<"Maximul este: "<<max<<endl; }
4. Se citeste un sir de la tastatura pana la intalnirea caracterului "$". Dupa citire datele se
scriu intr-un fisier text si se preiau din fisierul respectiv si se face contorizarea fiecarei
vocale din fisier. #include<iostream.h> #include<fstream.h> #include<stdio.h> void main() { char c; int a=0,e=0,i=0,o=0,u=0; ofstream f("d:\\ LaboratorOOP\\numar.txt "); if(!f) { cout<<"Eroare la deschidere."<<endl; } do{ c=getchar(); switch(c) { case 'a': a++; break; case 'e': e++; break; case 'i': i++; break; case 'o': o++; break; case 'u': u++; } if(c!='$') f.put(c); //ar fi mers si f<<c; }while(c!='$'); f.close(); ofstream g("d:\\ LaboratorOOP\\numar.txt "); if(!g) { cout<<"Eroare la deschidere fisierului de citire."<<endl; } g<<"Vocala a se gaseste de : "<<a<<" ori.\n"; g<<"Vocala e se gaseste de : "<<e<<" ori.\n"; g<<"Vocala i se gaseste de : "<<i<<" ori.\n"; g<<"Vocala o se gaseste de : "<<o<<" ori.\n"; g<<"Vocala u se gaseste de : "<<u<<" ori.\n"; g.close(); cout<<"Opratia de contorizare a vocalelor a reusit!"<<endl; }
14
5. Sa se sumeze valorile numerice dintr-un fisier text. #include<iostream.h> #include<string.h> #include<stdlib.h> #include<fstream.h> #include<stdio.h> void main() { char a[255], separator[]=" ,",cifre[]="0123456789.+-",*p; double s=0; fstream f("valori.txt",ios::in); if(!f) { cout<<"Eoare la deschiderea fisierului."<<endl; return; } while(!f.eof()) { f.getline(a,255,'\n'); p=strtok(a,separator); //se separa sirul folosind ca separator spatiul sau virgula while (p) { if (strspn(p,cifre)==strlen(p)) s+=atof(p); cout<<p<<"\n"; p=strtok(NULL,separator); } } cout<<"Suma este: "<<s<<endl; }
6. Sa se realizeze un program care tine in evidenta o agenda telefonica. Se vor
supraincarca operatorii << si >>, precum se cere lucrul cu fisiere cu transfer in si din
fisier. #include<iostream.h> #include<fstream.h> #include<string.h> class agendatelefon { char nume[80]; int codzona; int prefix; char numar[11]; public:
15
friend ostream &operator<< (ostream & stream, agendatelefon o); friend istream &operator>> (istream & stream, agendatelefon &o); }; //Afiseaza numele si numarul de telefon ostream &operator<< (ostream &stream, agendatelefon o) { stream<<o.nume<<" "; stream<<"("<<o.codzona<<")"; stream<<o.prefix<<"-"; stream<<o.numar<<"\n"; return stream; } //Introduce nume si numere de telefon istream &operator>>(istream &stream,agendatelefon &o) { cout<<"Introduceti numele: "; stream>>o.nume; cout<<"Introduceti coudul zonei: "; stream>>o.codzona; cout<<"Introduceti prefixul: "; stream>>o.prefix; cout<<"Introduceti numarul: "; stream>>o.numar; cout<<'\n'; return stream; } void main() { agendatelefon a; char c; fstream f("telefon.txt",ios::in| ios::out| ios::app); if(!f) { cout<<"Nu pot deschide fisierul agenda de telefon\n"; return; } do { cout<<endl; cout<<"1. Introduceti abonat de la tastatura cu afisare pe ecran si in fisier\n"; cout<<"2. Afiseaza lista abonati pe ecran cu preluare din fisier\n"; cout<<"3. Parasiti programul\n"; cout<<"Alegeti optiunea: "; cin>>c; switch(c) { case '1':
16
cin>>a; cout<<"Intrarea este: "; cout<<a; //afiseaza pe ecran f<<a; /* scrie in fisier (este una dintre cele mai interesante facilitati ale limbajului, adica, odata supraincarcat oeratorul << ni se permite scrierea directa in fisier) */ break; case '2': char ch; f.seekg(0,ios::beg); while(!f.eof()) { f.get(ch); cout<<ch; } cout<<endl; break; case '3': f.close(); } } while(c!=3); }
7. Operatii pe fisiere binare. Calculul minimului si maximului dintr-un fisier ce contine
numere intregi. #include<iostream.h> #include<fstream.h> void main(void) { int v[4]={1, -5, 200, 98}; int i; ofstream out("numere.dat",ios::out|ios::binary); if(!out) { cout<<"Nu pot deschide fisierul.\n"; return; } out.write((unsigned char*) &v, sizeof v); out.close(); for(i=0;i<4;i++) v[i]=0; //curatim matricea ifstream in("numere.dat",ios::in|ios::binary); if(!in) { cout<<"Nu pot deschide fisierul.\n";
17
return; } in.read((unsigned char*) &v, sizeof v); //aflati cati octeti au fost cititi cout<<in.gcount()<<" octeti cititi.\n"; int max, min; max=v[0]; min=v[0]; for(i=1;i<4;i++) if(v[i]<min) min=v[i]; else if(v[i]>max) max=v[i]; for(i=0;i<4;i++) cout<<v[i]<<" "; cout<<endl<<"Maximul este:"<<max<<'\t'<<"minimul este: "<<min<<endl; in.close(); }
Teme propuse spre rezolvare:
1. Se citeşte un fişier text format din valori intregi despartite prin spatiu sau enter. Sa
se calculeze numarul de numere pozitive şi suma lor, respectiv, numarul de
numere negative si suma lor.
2. Problema cu agenda telefonica din acest laborator sa se modifice pentru lucrul cu
fisiere binare.
3. Asemanatoare problemei cu agenda telefonica sa se enunţe si rezolve o problema
folosind fişiere binare.
Lect. Univ. Mircea Musan