Sunteți pe pagina 1din 10

L14 OPERAII DE INTRARE/IEIRE CU FIIERE N C++

Modelul fundamental pentru construcia bibliotecii IOSTREAM este cel de stream, vzut ca un flux de date de la o anumit surs la o anumit destinaie. Aceast bibliotec const din mai multe clase, organizate n dou ierarhii paralele.
a)

O ierarhie de clase streambuf, care realizeaz gestionarea bufferelor utilizate de fluxuri, n efectuarea operaiilor de intrare/ieire. Obiecte ale clasei filebuf, care este o clas derivat a clasei streambuf, sunt folosite la prelucrarea fiierelor. Aceste obiecte sunt folosite de clase specifice pentru operaii cu fiiere, care sunt cuprinse n ierarhia care pornete de la clasa de baz ios. O ierarhie de clase ios, care gestioneaz toate operaiile de intrare/ieire, i pune la dispoziie o interfa la nivel nalt pentru programator. Aceast ierarhie folosete motenirea multipl n obinerea clasei derivate iostream, pentru c ea motenete att clasa istream, pentru realizarea operaiilor de intrare, ct i clasa ostream, pentru realizarea operaiilor de ieire. #n aceast ierarhie, sunt definite clasele derivate fstreambase, istream i ostream, avnd clasa de baz ios.

b)

Avnd n vedere faptul, c cele mai uzuale fiiere sunt cele de pe disc, ne vom ocupa de operaii de prelucrare a fiierelor nregistrate pe discuri. Pentru a efectua operaii de intrare/ieire cu fiiere, trebuie inclus n program fiierul antet FSTREAM.H. n acest fiier sunt definite: 1) clasa ifstream, pentru operaii de intrare (citire), care este o clas derivat de la clasele fstreambase i istream; 2) clasa ofstream, pentru operaii de ieire (scriere), care este o clas derivat de la clasele fstreambase i ostream; 3) clasa fstream, pentru operaii de intrare/ieire (citire/scriere), care este o clas derivat de la clasele fstreambase i iostream; n ierarhia de clase ios, se afl definite i clasele: 1) istream_withassign, derivat de la clasa istream; 2) ostream_withassign, derivat de la clasa ostream; 3) iostream_withassign, derivat de la clasa iostream; n construcia acestor clase derivate se adug definiia operatorului de atribuire (=) i sunt utile n redirecionarea operaiilor de intrare/ieire prin atribuirea unui flux, unui alt flux. Prelucrarea unui fiier de pe disc ncepe cu operaia de deschidere a sa. Deschiderea unui fiier se poate realiza: a) folosind funcia membr open ca un obiect al uneia din clasele ifstream, ofstream sau fstream instaniat fr parametri. b) crearea unei instane a clasei ifstream (pentru citire), ofstream (pentru scriere), sau fstream (pentru citire/scriere);

#n situaia a), dup ce s-a creat streamul, el este asociat unui fiier cu ajutorul funciei open( ). void open(const char*id_fiier, int mod, int acces=filebuf::openprot); unde: - id_fiier este numele fiierului care poate include i calea de acces; - mod precizeaz modul de deschidere al fiierului. El poate fi: ios::app // valoare util fiierului ce accept ieiri. Se adaug nregistrri la sfritul fiierului. ios::ate

145

// la deschiderea pentru prima dat a fiierului, poziionare la sfritul su. Operaiile de // intrare/ieire pot avea loc oriunde n interiorul fiierului. ios::binary // deschiderea unui fiier cu scopul de a fi prelucrat n binar (nu se accept modificri de // caractere). #n mod implicit fiierele se deschid n mod text (prelucrare pe caractere). ios::in // deschide fiier pentru citire (fiierul accept intrri). ios::out // deschide fiier pentru scriere (fiierul accept ieiri). ios::nocreate // deschiderea unui fiier existent (nu se deschide fiier n creare). ios::noreplace // nu se poate deschide un fiier existent pentru ieire, cu excepia situaiei n care sunt // operate ios::ate sau ios::app. ios::trunc // dac exist un fiier cu numele specificat este distrus i se creeaz un fiier nou.

Crearea unui stream folosind ifstream implic intrri i nu mai este necesar introducerea valorii ios::in. Crearea unui stream folosind ofstream implic ieiri i nu mai este necesar introducerea valorii ios::out. Majoritatea implementrilor indic tipul parametrului mod ca fiind int. Se pot combina dou sau mai multe valori ale lui mod, folosind operatorul logic OR ( | ).
-

parametrul acces are valoarea implicit filebuf::openprot, care indic acces la un fiier normal. n mod implicit, valoarea acestui parametru de protecie este 0.

Exemple: // deschideri de fiiere 1. ifstream fis; fis.open(f.dat, ios::nocreate); // se deschide fiierul existent f.dat, pentru citire. Opiunea ios::in este implicit. if(!fis) { cerr<<Deschidere eronat ! \n; exit(1); } else {....} 2. ofstream fis; fis.open(fisa.dat); // deschiderea unui fiier normal de ieire. Opiunea ios::out este implicit. if(!fis) { cerr<<Deschidere eronat ! \n; exit(1); } else {....} 3. ofstream fis; fis.open(pers.dat, ios::app | ios::binary); // se deschide fiierul binar pers.dat, pentru adugare de nregistrri la sfrit. if(!fis) {

146

cerr<<Deschidere eronat ! \n; exit(1); } else {....}

n situaia b) , instanierea obiectelor claselor ifstream, ofstream, fstream, produc apelul constructorilor necesari instanierilor, care apeleaz n mod automat, funcia de deschidere open( ). Aceti constructori au aceiai parametri ca i funcia de deschidere. Se procedeaz astfel: 1) # include <fstream.h> 2) se definesc clasele ifstream/ofstream; 3) se deschide fiierul cu numele id_in_fis / id_out_fis pentru operaii de intrare / ieire; 4) conectez fiierul la instana ifstream inf/ ofstream outf; ifstream inf(id_in_fis); ofstream outf(id_out_fis); 5) se verific corectitudinea operaiei de creare a fluxului, prin suprancrcarea operatorului logic de negare (!) pentru clasele de fluxuri; if(!inf) { cerr<<Eroare n operaia de deschidere a fiierului !\n; exit(1); }

Aadar, se poate deschide un fiier i conecta la un flux, n momentul crerii fluxului. Conectarea unui fiier la o instan ifstream (flux pentru intrare), este echivalent n ANSI C, cu apelul funciei fopen cu modul r. Conectarea unui fiier la o instan ofstream (flux pentru ieire), este echivalent n ANSI C, cu apelul funciei fopen cu modul w. Exemple: // deschideri de fiiere. Se rescriu, n aceast ipotez, exemplele anterioare.

1. ifstream fis (f.dat, ios::nocreate); if(!fis) { cerr<<Deschidere eronat ! \n; exit(1); } else {....} 2. ofstream fis(fisa.dat); if(!fis) { cerr<<Deschidere eronat ! \n; exit(1); } else {....} 3. ofstream fis(pers.dat, ios::app | ios::binary); if(!fis) { cerr<<Deschidere eronat ! \n; exit(1); } else {....}

147

Dup ncheierea procesului de prelucrare a fiierului, care a fost deschis, el trebuie nchis. nchiderea unui fiier se realizeaz cu ajutorul funciei membr close( ). obiect.close( ); sau ptr_obiect->close( ); unde obiect este o instaniere a uneia din clasele ifstream, ofstream sau fstream, iar ptr_obiect este un pointer spre unul din tipurile implementate prin aceste clase. Exemplu: fis.close( ); // funcia close( ) nu are parametri i nu returneaz nici o valoare.

n prelucrarea fiierelor tip text existente pe disc, se pot folosi funciile membre ale claselor istream, ostream i iostream, pentru c ele sunt clase de baz pentru clasele specifice prelucrrii fiierelor pe disc. Ca atare, se pot folosi operatorii de inserare/extragere (<< , >>), pentru operaii de scriere/citire cu format, ntr-un/ dintr-un fiier de pe disc. Se vor nlocui cin i cout cu un stream conectat cu fiierul respectiv. Exemplu: // se creeaz un fiier de eviden a unor persoane, care conine numele i vrsta. # include<iostream.h> # include<fstream.h> main( ){ ofstream fis_o(FISA); if(! fis_o){ cout<<Eroare la deschidere ! \n; return 1; } fis_o<<Popescu<<25<<ani<<endl; fis_o<<Georgescu<<40<<ani<<endl; fis_o<<Marinescu<<56<<ani<<endl; fis_o.close( ); return 0; }

// program prin care se citete i se afieaz coninutul fiierului precedent. # include<iostream.h> # include<fstream.h> main( ){ ifstream fis_i(FISA); if (! fis_i){ cout<<Eroare la deschiderea lui fis_i\n; return 1; } char nume25]; int varsta; fis_i>>nume>>varsta; cout<< nume<<:<<varsta<<\n; fis_i>>nume>>varsta; cout<< nume<<:<<varsta<<\n; fis_i>>nume>>varsta; cout<< nume<<:<<varsta<<\n; fis_i.close( ); return 0; }

n prelucrarea fiierelor de tip binar, exist dou posibiliti de citire/scriere a datelor. a) utilizarea funciilor membre de:

148

- intrare (citire) istream &get(char &ch); (citete un caracter din streamul asociat i memoreaz valoarea n ch, apoi returneaz o referin ctre stream). Funcia get( ) poate fi suprancrcat sub una din formele urmtoare: 1) istream&get(char*bf, int nr, char dl=\n); (citete nr caractere dintr-un tablou bidimensional indicat de bf. n cazul n care se ntlnete caracterul precizat prin dl (delimitator), funcia va ncheia cu null tabloul respectiv. Un astfel de caracter, n mod implicit, este caracterul de linie nou. Dac delimitatorul este ntlnit n streamul de intrare, el nu este extras i rmne n stream pn la urmtoarea operaie de citire.) 2) int get( ); (returneaz urmtorul caracter din stream sau EOF dac se ntlnete sfritul de fiier). Spre deosebire de funcia istream&get(char*bf, int nr, char dl=\n); funcia istream&getline(char*bf, int nr, char dl=\n); n plus, citete i extrage delimitatorul din streamul de intrare. - ieire (scriere) ostream &put(char ch); ( scrie ch n stream i returneaz o referin ctre stream). b) utilizarea funciilor de citire/scriere, n C++, a unor blocuri de date n binar: - intrare (citire) istream&read(unsigned char*bf, int nr); (citete nr octei din streamul asociat i i plaseaz n bufferul indicat de bf. Dac se ajunge la sfritul fiierului dup un numr nr_1<nr de octei (caractere) citii, operaia de citire se ncheie, iar n buffer se vor gsi caracterele citite.). Evidena numeric a octeilor existeni n buffer se poate stabili cu ajutorul funciei membre: int gcount( ); - ieire (scriere) ostream&write(const unsigned char*bf, int nr); (scrie n streamul asociat nr octei pe care i citete din bufferul indicat de bf). Exemplu: //program utilitar de copiere a unui fiier surs ntr-un fiier destinaie #include<fstream.h> #include <iostream.h> #include<string.h> main(int argc, char*argv[]){ fstream infis,outfis; if (argc>1){ // se specifica fisierul de intrare infis.open(argv[1],ios::in|ios::binary); if(!infis) { cerr<<"Eroare la deschiderea fis_intrare"<<argv[1]<<"\n"; return (1); } } if(argc>2){ // se specifica fisierul de iesire outfis.open(argv[2],ios::out); if(!outfis) {

149

cerr<<"Eroare la deschiderea fis_iesire"<<argv[2]<<"\n"; return (1); } } const dimbuf=255; char buf[dimbuf]; while(infis.get(buf,dimbuf,'\n')&&outfis) outfis.write(buf,strlen(buf)); return 0; } Exemplu: //utilizarea funciilor read( ) ]i write( ) # include<iostream.h> # include<fstream.h> # include<string.h> typedef struct { int zi; int luna; int an; }data_c; main( ){ data_c dt; dt.an=1999; dt.luna=12; dt.zi=25; ofstream outfis("termen",ios::out|ios::binary); if(!outfis) { cout<<"Eroare la deschidere.\n"; return (1); } outfis.write((unsigned char*)&dt, sizeof(data_c)); outfis.close(); ifstream infis("termen",ios::in|ios::binary); if(!infis) { cerr<<"Eroare la deschderea fis infis\n"; return (1); } infis.read((unsigned char*)&dt, sizeof(data_c)); cout<<dt.an<<endl; cout<<dt.luna<<endl; cout<<dt.zi<<endl; infis.close( ); return 0; } Alte funcii utile n prelucrarea unui fiier: 1) int eof( ); (returneaz valoarea 0, dac s-a ntlnit sfritul de fiier, sau diferit de zero, n caz contrar). 2) istream&ignore(int nr(=1), int dl=EOF); (citete i elimin, din streamul de intrare, un numr de nr caractere sau pe cele ntlnite pn la delimitatorul dl. Nu extrage delimitatorul din streamul de intrare.) 3) int peek( );

150

(returneaz urmtorul caracter din streamul de intrare sau EOF dac s-a ntlnit sfritul de fiier) 4) istream&putback(char ch); (returneaz, n acelei stream, ultimul caracter citit ch) 5) ostream&flush( ); (solicit scrierea efectiv a datelor pe disc, nainte de umplerea bufferului) Specificarea poziiei relative, ntr-un fiier, n raport cu un anumit punct de referin (acces aleator): a) istream&seekg(streamoff offset, seek_dir orig); b) ostream&seekp(streamoff offset, seek_dir orig); unde streamoff este un tip definit n iostream.h, apt de a reine cea mai mare valoare valid a lui offset, iar seek_dir const ntr-o enumerare cu urmtoarele valori: ios::beg // nceput de fiier ios::cur //poziia curent ios::end// sfrit de fiier Sistemul de intrare/ieire din C++ opereaz cu un pointer get, care precizeaz poziia urmtoarei operaii de intrare n fiier, i un pointer put, care precizeaz poziia urmtoarei operaii de ieire n fiier. Dup fiecare operaie, pointerul respectiv avanseaz, n mod secvenial. Funciile menionate permit un acces nesecvenial la fiierul care urmeaz a fi prelucrat. Funcia seekg( ) deplaseaz pointerul get al fiierului asociat cu un numr de octei dat de valoarea offset n raport cu originea menionat prin orig. Funcia seekp( ) deplaseaz pointerul put al fiierului asociat cu un numr de octei dat de valoarea offset n raport cu originea menionat prin orig. Utilizarea funciilor anterioare sub forma a) istream&seekg(streampos p); c) ostream&seekp(streampos p); permit salvarea poziiei curente a fiierului, efectund alte operaii pe fiier, i revenind la poziia salvat anterior. Tipul definit n iostream.h, streampos, este apt de a reine cea mai mare valoare pe care o poate returna una din cele dou funcii. Starea curent a sistemului de intrare/ieire este reinut ntr-un ntreg n care se afl codificai urmtorii indicatori ( enumerai n clasa ios): a) eofbit // 1 pentru sfrit de fiier i 0 n caz contrar Funcia int eof( ); // returneaz o valoare nenul (adevrat) dac este activat eofbit b) badbit // 1 cnd apare o eroare fatal i 0 n caz contrar Funcia int bad( ); // returneaz o valoare nenul (adevrat) dac este activat badbit c) failbit // 1 cnd apare o eroare de intrare/ieire i 0 n caz contrar Funcia int fail( ): // returneaz o valoare nenul (adevrat) dac este activat failbit d) goodbit // valoarea 0 (fr eroare) Funcia int good( ); // returneaz adevrat dac nu exist erori i 0 n caz contrar.

151

Starea curent a sistemului de intrare/iere se poate stabili prin apelarea funciilor menionate anterior, sau prin funcia: int rdstate( );// returneaz 0 dac nu exist erori.

Aplicaie: S se scrie un program care s citeasc de la intrarea standard date cu urmtorul format: cod_acces den_tren nr_tren viteza nr_vag. S se scrie, prin programul respectiv, datele din directorul curent n fiierul tren.dat. #include<iomanip.h> #include<stdlib.h> #include<fstream.h> typedef struct { char cod_acces; char den_tren[15]; int nr_tren; int viteza; int nr_vag; }tren; union{ tren p[3]; char pt[3*sizeof(tren)]; }tamp; int citinf(tren*ptr) { char tab[255]; int v,nr; for(;;) { cout<<"cod_acces den_tren nr_tren viteza nr_vag"; if((cin>>setw(4)>>ptr->cod_acces)&&(cin>>setw(15)>>ptr->den_tren)&& (cin>>setw(4)>>ptr->nr_tren)&&(cin>>v>>nr)) { ptr->viteza=v; ptr->nr_vag=nr; return 1; } if(cin.eof( )) return 0; //EOF cin.clear( ); // anuleaza eroarea cin.getline(tab,255,'\n'); } } main( ){ // se creeaza fisierul binar "tren.dat" ofstream trafic("tren.dat",ios::binary); int k; if(!trafic){ cout<<"Eroare la deschiderea fisierului in creare\n"; exit(1); } for(; ; ){ for(int j=0;j<3;j++) if((k=citinf(&tamp.p[j]))==0)break; //EOF if(j){ // zona tampon este nevida

152

trafic.write(tamp.pt,j*sizeof(tren)); if(!trafic){ cout<<"Eroare la scriere in fisier"; exit(1); } } if(k==0)break; // EOF } trafic.close( ); } S se scrie un program care s afieze datele din fiierul creat tren.dat, conform cod_acces solicitat. #include<iomanip.h> #include<stdlib.h> #include<fstream.h> typedef struct { char cod_acces; char den_tren[15]; int nr_tren; int viteza; int nr_vag; }tren; union{ tren p[3]; char pt[3*sizeof(tren)]; }tamp; main( ){ // se creeaza fisierul binar "tren.dat" ifstream trafic("tren.dat",ios::binary); int k; if(!trafic){ cout<<"Eroare la deschiderea fisierului in creare\n"; exit(1); } cout<<"\n\n"<<setw(19)<<"INSTANTA"<<"\n\n"; do{ trafic.read(tamp.pt,3*sizeof(tren)); k=trafic.gcount()/sizeof(tren); for(int j=0;j<k;j++) { if((tamp.p[j].cod_acces=='2')|(tamp.p[j].cod_acces=='0')) { cout<<"\n"; cout.setf(ios::right,ios::adjustfield); cout<<setw(1)<<tamp.p[j].cod_acces; cout.setf(ios::left,ios::adjustfield); cout<<' '<<setw(15)<<tamp.p[j].den_tren; cout.setf(ios::left,ios::adjustfield); cout<<setw(4)<<tamp.p[j].nr_tren; cout<<tamp.p[j].viteza; cout<<' '<<setw(3)<<tamp.p[j].nr_vag; }}

153

}while(trafic); if(!trafic.eof( )) cout<<"Citire eronata!\n"; trafic.close( ); } Tematic propus 1. S se realizeze un program de copiere a unui fiier de tip text de pe disc sau pe disc. 2. S se scrie un program prin care s se afieze coninutul unui fiier cunoscut. 3. S se scrie un program care s citeasc iruri de caractere de la intrarea standard i s le transfere ntr-un fiier pe disc. 4. S se realizeze concatenarea a dou fiiere surs ntr-un al treilea fiier destinaie. 5. S se realizeze programe prin care s se pun n eviden modul de utilizare a funciilor de poziionare ntr-un fiier.

154

Evaluare