Curs 13

17
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 13 Sumar 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

description

Programare - Prelucrarea Fisierelor

Transcript of Curs 13

Page 1: 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

Page 2: Curs 13

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

Page 3: Curs 13

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

Page 4: Curs 13

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);

Page 5: Curs 13

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”;

Page 6: Curs 13

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”;

Page 7: Curs 13

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();

Page 8: Curs 13

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.

Page 9: Curs 13

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);

Page 10: Curs 13

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

Page 11: Curs 13

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();

Page 12: Curs 13

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;

Page 13: Curs 13

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; }

Page 14: Curs 13

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:

Page 15: Curs 13

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':

Page 16: Curs 13

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";

Page 17: Curs 13

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