Documente Academic
Documente Profesional
Documente Cultură
INTRRI/IEIRI
13.1. Principiile de baz ale sistemului de I/O din limbajul C++ 13.2. Testarea i modificarea strii unui flux 13.3. Formatarea unui flux 13.3.1. Formatarea prin manipulatori 13.3.2. Formatarea prin metode 13.4. 13.5. 13.6. 13.7. 13.8. Metodele clasei istream Metodele clasei ostream Manipulatori creai de utilizator Fluxuri pentru fiiere Fiiere binare
fiiere
Figura 13.1. Stream-ul - baza sistemului de I/O Avantajele utilizrii stream-urilor sunt: Flexibilitate mare n realizarea operaiilor de I/O (mai mare dect n cazul folosirii funciilor din C); Posibilitatea de eliminare a erorilor care apar n mod frecvent la apelul funciilor de I/O obinuite, cnd numrul specificatorilor de format difer de cel al parametrilor efectivi;
205
CAPITOLUL 13 Intrri/ieiri
Posibilitatea de a realiza operaii de I/O nu numai cu date de tipuri predefinite, ci i cu obiecte de tip abstract. Biblioteca de clase de I/O a limbajului C++ utilizeaz motenirea, polimorfismul i clasele abstracte. Ierarhia are dou clase de baz (figura 13.2.): Clasa virtual ios care ofer informaii despre fluxurile de date (variabile de stare, metode) i faciliti tratarea erorilor; Clasa streambuf (clas prieten cu ios), destinat operaiilor de I/O cu format.
ios
streambuf
istream
ostream
strstreambase
fstreambase
iostream
ifstream
ofstream
fstream
filebuf
Figura 13.2. Ierarhia claselor de intrare/ieire Utilizarea ierarhiilor de clase de mai sus implic includerea headerului iostream.h. Clasa ios are un pointer ctre streambuf. Are date membru pentru a gestiona interfaa cu streambuf i pentru tratarea erorilor. Clasele derivate din clasa de baz ios: Clasa istream, care gestioneaz intrrile: class istream:virtual public ios Clasa ostream gestioneaz ieirile: class ostream: virtual public ios Clasa iostream, derivat din istream i ostream, gestioneaz intrrile i ieirile. Fiecrui flux de date i se asociaz n memorie o zon tampon numit buffer. Clasa furnizeaz funcii generale pentru lucrul cu zonele tampon i permite tratarea operaiilor de I/O fr a avea n vedere formatri complexe. class iostream:public istream, public ostream Clasele istream, ostream i iostream sunt, fiecare, clase de baz pentru clasele derivate: class istream_withassign:public istream class ostream_withassign:public ostream class iostream_withassign:public iostream Clasele cu sufixul _withassign furnizeaz urmtoarele fluxurile predefinite (instane), deja cunoscute: 1. cout (console output) obiect al clasei ostream_withassign, similar fiierului standard de ieire definit de pointerul stdout (n C). Se folosete cu operatorul insertor, suprancrcat pentru tipurile predefinite: Exemplu: int n; cout<<n; Convertete din format binar n zecimal valoarea lui n, i trimite (insereaz) n fluxul cout caracterele corespunztoare fiecrei cifre obinute. 2. cin (console input) obiect al clasei istream_withassign, similar fiierului standard de intrare definit de pointerul stdin (n C). A fost folosit cu operatorul extractor, suprancrcat pentru tipurile predefinite: Exemplu: int n; cin>>n;
206
CAPITOLUL 13 Intrri/ieiri
Extrage din fluxul de intrare caracterele corespunztoare, le convertete din zecimal n binar i le depune n memorie. 3. cerr: flux de ieire conectat la ieirea standard pentru erori (stderr n C) (fr buffer intermediar). 4. clog: flux de ieire conectat la ieirea standard pentru erori (fr buffer intermediar). Clasa streambuf este clas prieten cu ios. Ea furnizeaz funcii generale pentru lucrul cu zonele tampon (buffere) i permite tratarea operaiilor de I/O fr formatri complexe. Din clasa streambuf deriva clasa filebuf . S urmrim care este rolul buffere-lor (zon tampon asociat fiecrui flux de date), prin urmtorul exemplu: Exemplu:
void main() {int a; double x; char sir[20]; cin>>a>>x>>ir; cout<<a<<' '<<x<<endl; cout<<sir<<endl; }
Memorie intern
a
date de intrare
x sir
Compilatorul verific dac numrul introdus este ntreg (se oprete cnd ntlnete altceva dect o cifr: n acest caz - un blanc). l citete printr-o metod a tipului int, l convertete n binar i l transmite n memoria intern n spaiul rezervat pentru variabila a. n ncheiere, cin>>a devine cin. cin>>a>>x; // fluxul de date se transmite i lui x Presupunem c am introdus de la tastatur 325 17.45e5 exemplu de ir, valorile pentru a, x i sir. La apsarea tastei Enter, se transmite ctre sistemul de operare un octet cu semnificaia de sfrit introducere date. Sistemul de operare transmite un semnal zonei tampon i abia acum se transmite valoarea (fluxul de date) lui a. La citirea irului de caractere (pn la primul blank), se transfer octet cu octet (i se adaug automat caracterul NULL), din zona tampon n memoria intern. Observaii: 1. Stream-ul este secvenial. 2. El poate realiza intrri/ieiri formatate. 3. Este bine c n cazul unui flux de intrare s se verifice mai nti dac n zona tampon se gsete ceva. Dac nu, se poziioneaz cursorul la nceputul zonei tampon. 4. Informaia de la buffer ctre memorie este gestionat prin program; informaia de la zona tampon ctre alte periferice este gestionat de ctre sistemul de operare.
CAPITOLUL 13 Intrri/ieiri
(o mulime de indicatori de stare), care pstreaz toate informaiile aferente erorilor aprute n cursul operaiilor cu stream-ul. Aceti indicatori sunt memorai la nivel de bit n data membru state.
class ios{ // protected: int state; public:
//pstreaz la nivel de bit valorile indicatorilor de stare //ultima operaie de intrare/ieire corect //s-a ntlnit sfritul de fiier ntr-o operaie de intrare (lipsa //caracterelor disponibile pentru citire) //setat dac ultima operaie de intrare/ieire a euat; stream-ul //respectiv nu va mai putea fi folosit n operaii de I/O pn cnd //bitul nu va fi ters //ultima operaie de intrare/ieire invalid; n urma resetrii flag-ului //este posibil ca stream-ul s mai poat fi utilizat //eroare irecuperabil
};
Testarea valorii cuvntului de stare asociat unui stream se realizeaz cu ajutorul metodelor: int good();//Returneaz valoare diferit de zero dac cuvntul de stare este 0 int eof();//Returneaz valoare diferit de zero dac eofbit este setat int fail();//Returneaz valoare diferit de zero dac failbit, hardbit sau badbit sunt setai int bad();//Funcioneaz ca metoda fail, dar nu ia n considerare flagul failbit. Modificarea valorii cuvntului de stare asociat unui stream se realizeaz cu ajutorul metodelor: void clear(int i=0); Seteaz data membru state la valoarea parametrului (implicit 0). Este capabil s tearg orice flag, cu excepia flag-ului hardfail. Exemplu:: a.clear(ios::badbit); Seteaz bitul failbit i anuleaz valorile celorlai bii din cuvntul de stare a fluxului a. Pentru ca ceilali bii s rmn nemodificai, se apeleaz metoda rdstate. Exemplu: a.clear(a.rdstate()|val_f); Se seteaz un singur flag, lsndu-le nemodificate pe celelalte; val_f are una din valorile definite de enumerarea io_state. int rdstate(); Returneaz valoarea cuvntului de stare, sub forma unui ntreg (valoarea datei membru state). Exemplu: a.clear(ios::badbit | a.rdstate()); Seteaz bitul failbit, fr a modifica valorile celorlali bii: Testarea cuvntului de stare se poate realiza i prin folosirea operatorilor ! i void* : Operatorul ! este suprancrcat printr-o funcie membr, cu prorotipul: int operator ! (); care returneaz 0 dac un bit de eroare din cuvntul de stare este setat (ca i metoda fail). Exemplu: if (!cin) //echivalent cu if (!cin.good())
else
Operatorul void* convertete stream-ul ntr-un pointer generic. Conversia are ca rezultat zero dac cel puin un bit de eroare este setat: operator void *();
208
CAPITOLUL 13 Intrri/ieiri
Exemplu: O construcie de forma: cin>>s; are ca valoare o referin la stream-ul cin, din clasa istream. Aceast referin poate fi utilizat sub forma: if (cin>>s). . . Pentru scoaterea unui stream din starea de eroare, fie dispare cauza erorii, fie trebuie terse flagurile care semnalizeaz eroarea.
//pstreaz la nivel de bit indicatorii de format //numrul de caractere utilizate pentru afiarea unei valori pe ecran // salt peste spaiile albe de la intrare // aliniere la stnga la ieire // aliniere la dreapta la iesire // aliniere dup semn sau specificator al bazei la ieire // conversie n baza 10 // conversie octal la intrare/ieire // conversie hexa la intrare/ieire // afiarea bazei la ieire // afiarea punctului zecimal pentru numere reale la ieire // afiarea cu majuscule a cifrelor hexa i a literei E la ieire. // afiarea semnului + pentru numerele pozitive la ieire //folosirea formatului exponenial (tiinific) pentru numerele reale // folosirea formatului n virgul fix pentru numere reale la // golete zona tampon dup fiecare ieire // golete "stdout" i "stdin" dup fiecare inserare
n figura 13.4. sunt prezentate numele cmpurilor de bii (acolo unde este cazul). n cadrul fiecrui cmp de bii (adjustfield, basefield, floatfield) un singur bit poate fi activ.
floatfield floatfield scientific uppercase showpoint showbase basefield adjustfield
internal
unitbuf
showpos
right
oct
209
hex
dec
left
skipws
fixed
CAPITOLUL 13 Intrri/ieiri
Modificarea cuvntului de format se poate realiza n urmtoarele moduri: 1. Cu ajutorul manipulatorilor (cu sau fr parametri); 2. Cu ajutorul unor funcii membre ale claselor istream sau ostream.
210
CAPITOLUL 13 Intrri/ieiri
lsnd restul biilor nemodificai (dezactiveaz indicatorii specificai de f) setiosflags (long f) I/O Atribuie valoarea 1 tuturor biilor indicai de argument, lsnd restul biilor nemodificai (activeaz indicatorii specificai de f) setfill (int c) I/O Definete caracterul de umplere (cel implicit este spaiul liber, blank-ul) setprecision (int p) I/O Definete precizia pentru numerele reale setw (int w) I/O Definete limea cmpului (numrul de octei care vor fi citii sau afisai) Utilizarea manipulatorilor impune includerea header-ului iomanip.h. Exerciiu: Exemplificarea modului de folosire a manipulatorilor pentru intrri/ieiri formatate.
#include <iostream.h> #include <iomanip.h> void main() {int a,b,c;double alfa,x,y;long ll;char xx,yy; float u,v; unsigned int w; unsigned char ab,db; a=125,b=10; ll=100*a*b; cout<<"100*a*b="<<ll<<endl; //100*a*b=-6072 alfa=75.50;y=1.345678; xx=35;yy=6; x=y/alfa-xx/yy; cout<<"x="<<x<<endl; //x=-4.982176
//setarea mrimea cmpului de afiare //x=-4.982176 //x= -4.982176 //setarea lungimii cmpului de afiare i a caracterului de umplere cout<<"x="<<setw(20)<<setfill('*')<<x<<endl; //x=***********-4.982176 // precizie cout<<"x="<<setw(8)<<setprecision(2)<<x<<endl; //x=***-4.98 cout<<"x="<<setw(8)<<setprecision(0)<<x<<endl; //x=-4.982176 // afisarea octetului semnificativ var & 0377 si a celui mai putin semnificativ (var>>8) & 0377
cout<<"x="<<setw(8)<<x<<endl; cout<<"x="<<setw(20)<<x<<endl; w=34; ab='34' & 0377; db=('34'>>8)&0377; cout<<"w="<<w<<" ab="<<ab<<" db="<<db<<endl; u=2579.75;v=12345.567E+10;
//b=10
Funcia membr setf permite modificarea cuvntului de stare a formatrii. Ea este supradefinit astfel: long setf (long) ; Primete ca parametru un numr ntreg long i seteaz pe 1 biii specificai prin argument. Returneaz valoarea anterioar a cuvntului de stare a formatrii. Ea poate fi folosit numai pentru flag-urile care nu fac parte dintr-un cmp de bii. Exemplu: cout. setf (ios:: showpos); //seteaz bitul showpos pe 1 long setf (long flags, long field) ; Seteaz pe 1 biii specificai prin primul argument, doar n cmpul de bii definit ca al doilea argument. Ea modific pe 0 toi biii din cmpul respectiv, dup care seteaz (pe 1) bitul respectiv. Exemple:
211
CAPITOLUL 13 Intrri/ieiri cout. setf (ios:: showpos | ios :: uppercase | ios:: internal)
Funcia membr fill permite testarea sau modificarea caracterului de umplere i returneaz codul caracterului curent de umplere: int fill ( ) ; Exemplu: cout.fill ( ); // ntoarce codul caracterului de umplere pt. cout int fill (char) ; Seteaz noul caracter de umplere i returneaz codul vechiului caracter de umplere. Exemplu: cout.fill(# ); // seteaz un alt caracter de umplere ('#'). Funcia membr precision permite testarea sau modificarea preciziei. Numim precizie numrul de cifre semnificative (n GNU) sau numrul de cifre dup virgul (n TurboC) int precision ( ); Returneaz valoarea actual a preciziei numerice. int precision (int); Seteaz precizia la valoarea parametrului i returneaz vechea valoare a preciziei. Funcia membr width returneaz valoarea actual a lungimii cmpului de date sau seteaz valoarea lungimii cmpului de date. int width ( ) ; .int width (int) ; Exemplu: cout. width (10); //data se va afia ntr-un cmp de cel puin 10 caractere. Astfel, dac argumentul este 0, la inseria ntr-un flux de ieire se transmit n stream atia octei ci are data respectiv. Dac argumentul este diferit de 0, dar lungimea necesar afirii este mai mare, se transmite numrul de octei necesari; iar dac lungimea necesar afirii este mai mic, se transmite numrul de octei necesari, iar restul se completeaz cu caracterul de umplere.
Exerciiu:
#include <iostream.h> void main() {int i=123, j=456; double x=1234.567890123456, y=5678; cout.width(5); cout<<i<<' '<<j<<endl; //123 456 cout<<i; //toate metodele sunt persistente, cu excepia metodei width cout.width(5); cout<<j<<endl; //123 456 cout.setf(ios::showpos); //afis. + cout<<i<<' '<<j<<endl; //+123 +456 cout.setf(ios::hex, ios::basefield); cout.width(20); cout.precision(15); cout.fill('*'); cout.setf(ios::showpos | ios::showpoint); cout<<x<<' '<<y<<endl; //***+1234.56789012346 +5678.00000000000 cout<<i<<' '<<j<<endl; //7b 1c8 cout.setf(ios::dec, ios::basefield); cout.unsetf(ios::showpos); cout.fill(' '); cout<<i<<' '<<j<<endl; //123 456 cout<<x<<' '<<y<<endl; //1234.56789012346 5678.00000000000 }
Observaie: Toate metodele sunt persistente, cu excepia metodei width care este valabil numai pentru operaia urmtoare, dup care se seteaz la 0.
CAPITOLUL 13 Intrri/ieiri
Operatorul de extracie din stream-ul (fluxul) de intrare este suprancrcat printr-o funcie membr, pentru toate tipurile de baz. El are rolul de a extrage din fluxul de intrare caracterele necesare pentru a obine o valoare dintr-un tip de baz. istream & operator >> (&tip_de_baz); Primul argument este implicit (this): clasa care l apeleaz. Al doilea argument este o referin ctre un tip_ de_baz. Operatorul poate fi suprancrcat printr-o funcie prieten (vezi capitolul 11), pentru a extrage din fluxul de intrare informaiile despre un obiect dintr-un tip definit de utilizator (clas): friend istream & operator >>(istream &, clasa &); Metoda get istream & get (char &); Metoda extrage din fluxul de intrare un caracter i l memoreaz n variabila referin, transmis ca parametru. ntoarce o referin ctre istream. Exemplu: char c; cin.get(c); Metoda get este suprancrcat i astfel: int get ( ); Extrage din fluxul de intrare un singur caracter i l returneaz sub forma unui ntreg. Aceast metod este utilizat, n special, la testarea sfritului de fiier (EOF, -1). Metoda get este suprancrcat i astfel: istream & get (char * ir, int lungime, char delimitator = \n) Se extrage din fluxul de date de intrare un ir de caractere (char * ir = pointer ctre ir), cu lungimea maxim specificat prin argumentul lungime, pn la ntlnirea delimitatorului (delimitator nu se extrage din fluxul de date de intrare). Rezultatul se depune n variabila ir. Metoda getline Metoda determin preluarea din fluxul de intrare a unui ir de caractere, terminat cu un caracter cunoscut. istream & getline (char * ir, int lungime, char delimitator = EOF); Acioneaz asemntor cu metoda get suprancrcat prin ultima form, cu deosebirea c din fluxul de intrare se extrage i delimitatorul. Delimitatorul nu se introduce n ir. Exemplu: char ir[50];cin.get (ir, 50, \ n); // sau cin.get(ir, 50); Din fluxul de date de intrare se extrag caracterele pn la sfrit de linie, cel mult 50 de caractere. Extragerea caracterelor din fluxul de intrare se termin fie la ntlnirea terminatorului, fie atunci cnd s-a citit un numr de caractere egal cu lungime-1 . Metoda gcount returneaz un ntreg care reprezinat numrul efectiv de caractere preluat prin getline. int gcount(); Metoda read extrage din fluxul de intrare un ir de caractere (octei) de lungime impus i-l depoziteaz n zona de memorie ir. istream & read (char * ir, int lungime); Eemplu: char t[30]; cin.read(t, 20); Metoda ignore este utilizat la golirea zonei tampon a stream-ului de intrare. istream & ignore (int lungime, char delimitator = | ); Se extrag din fluxul de intrare caracterele pn la delimitator, dar nu mai multe dect numrul indicat de parametru lungime. Caracterele extrase sunt eliminate, nu sunt memorate. Metoda peck furnizeaz primul caracter din fluxul de intrare, fr a-l extrage ns din flux. Caracterul va fi primul caracter extras la urmtoarea citire. int peck( ); Exemplu: c = cin.peck ( ); Metoda putback insereaz n fluxul de intrare caracterul trimis ca argument. istream & putback(char &); Observaii: 1) int a; cin.get (a) cin >> a; 2) Metodele pot fi folosite n serie: Exemplu: cin.get(a).get(b).get (c);
213
CAPITOLUL 13 Intrri/ieiri
Supradefinirea operatorului de inserie << Operatorul de inserie n fluxul de ieire este suprancrcat printr-o funcie membr pentru toate tipurile de baz. El are rolul de a introduce (insera) n fluxul de ieire caracterele necesare pentru a afia o valoare dintr-un tip de baz. ostream & operator << (tip_de_baz); Primul argument este implicit (this). Al doilea argument este o expresie de tip de baz. Operatorul poate fi suprancrcat printr-o funcie prieten, pentru a insera n fluxul de ieire informaiile despre un obiect dintr-un tip definit de utilizator (clas): friend ostream & operator << (ostream &, clasa &); Metoda put insereaz n fluxul de date de ieire caracterul transmis ca parametru. ostream put (char); Exemple: char c='S'; cout . put ( c ); // echivalent cu cout << c;
char c1='A',c2='B',c3='C';cout.put(c1).put(c2).put(c3); //echivalent cu:cout.put(c1);cout.put(c2); cout.put(c3); // echivalent cu cout<<c1<<c2<<c3;
Metoda write insereaz n fluxul de date de ieire un numr de caractere, de lungime impus, existente n zona tablou. ostream & write (char * tablou, int lungime); Exemplu: char t[]="Bun ziua!\n"; cout.write(t, 4); //Insereaz n fluxul de ieire 4 caractere, ncepnd de la adresa t.
Exerciiu: Se ilustreaz formatarea unui flux de intrare/ieire att prin funcii membre, ct i cu ajutorul manipulatorilor (cu sau fr parametri).
#include <iostream.h> #include <iomanip.h> void main() {int i=123; char car, mesaj[]=" Apas tasta Enter\n"; cout<<setw(5)<<resetiosflags(ios::internal |ios::right); cout<<setiosflags(ios::left)<<setfill('#')<<i<<endl; cout<<setw(5)<<setiosflags(ios::showpos)<<setfill(' ')<<i<<endl; cout<<setw(5)<<resetiosflags(ios::left)<<setfill('0')<<setiosflags(ios::right); cout<<i<<endl; cout<<"\n hexagesimal:"<<setw(5)<<hex<<i<<endl; cout<<"\n octal:"<<setw(5)<<oct<<i<<endl; cout<<"\n zecimal:"<<setw(5)<<dec<<i<<endl; cout<<mesaj; cin.get(car); double d=123.456789012345678901234567890123456789; cout<<"Afisare d cu precizia implicit:"<<d<<endl; cout<<"Afisare d cu lung 25 si precizie 15:"<<setw(25)<<setprecision(15)<<d<<endl; cout<<"Schimbare caracter umplere &:"<<setw(25)<<setfill('&')<<d<<endl; cout<<endl; }
CAPITOLUL 13 Intrri/ieiri
istream &nume_manipulator (istream &); Crearea manipulatorilor cu parametri Crearea manipulatorilor fr parametri necesit folosirea a dou funcii: ostream & nume_manipulator (ostream &, int);
omanip <int> nume_manipulator (int n) // funcie ablon (template) cu parametru de tip int {return omanip <int> (nume_manipulator, n);} Deci, manipulatorii sunt funcii ale cror corpuri sunt stabilite de utilizator. Exemplu: n exemplul urmtor se definesc manipulatorii indentare (indentare = naintea liniei propriuzise, se las un numr de spaii albe), convhex (realizeaz conversia din zecimal n hexa), init (iniializeaz lungimea cmpului la 10 caractere, stbilete precizia la 4 i caracterul de umplere $).
#include <iostream.h> #include <iomanip.h> ostream &convhex (ostream &ies) {ies.setf(ios::hex, ios::basefield); ies.setf(ios::showbase); return ies;} ostream &indentare (ostream &ies, int nr_spaii) {for (int i=0; i<nr_spatii; i++) ies<<' '; return ies;} ostream &init (ostream &ies) {ies.width(10); stream.precision(4); ies.fill('$'); return ies;} omanip <int> indentare (int nr_spaii) {return omanip <int> (indentare, nr_spaii);} void main() {cout<<712<<' '<<convhex<<712<<endl; cout<<indentare(10)<<"Linia1 text\n"<<indentare(5)<<"Linia2 text\n"; cout init<<123.123456;}
CAPITOLUL 13 Intrri/ieiri
Fluxul nu este asociat nici unui fiier ifstream(const char *nume_fisier, int mod_acces=ios:in); Parametri constructorului sunt numele fiierului i modul de acces la acesta (citire, fiier de intrare). ifstream (int fd, char *buffer, int lung_buffer); Parametrii sunt numrul intern al fiierului (fd), zona tampon de intrri/ieiri (buffer) i lungimea zonei tampon (lung_buffer). Exemplu: Se declar obiectul numit fis_ies, de tipul ofstream, obiect asociat unui fiier cu numele DATE.txt, deschis apoi pentru ieire (scriere). Scrierea n fiierul asociat obiectului se face printr-un flux care beneficiaz de toate "facilitile" clasei ostream. ofstream fis_ies("DATE.txt", ios::out); //sau: ofstream fis_ies("DATE.txt"); Scrierea n fiierul DATE.txt: fis_ies<< . . . << . . .; Pentru scriere formatat sau scriere binar n fiierul asociat: fis_ies.write(. . . ); Pentru examinarea strii fluxului de eroare corespunztor: if (fis_ies) . . .; Se declar obiectul numit fis_intr, de tipul ifstream, obiect asociat unui fiier cu numele NOU.txt, deschis apoi pentru intrare (citire). Citirea din fiierul asociat obiectului se face printr-un flux care beneficiaz de toate "facilitile" clasei istream. ifstream fis_intr("DATE.dat", ios::in); //sau: ifstream fis_intr("NOU.txt"); Citirea n fiierul NOU.txt: fis_intr>> . . . >> . . .; Pentru citire formatat sau citire binar din fiierul asociat: fis_intr.read(. . . ); Pentru examinarea strii fluxului de eroare corespunztor: if (fis_intr) . . .; Observaii: Conectarea (asocierea) unui flux unui fiier presupune: Fie existena a dou tipuri de obiecte: un flux i un fiier; Fie declararea unui flux care va fi asociat ulterior unui fiier. Clasa fstream motenete att clasele ifstream, ct i ofstream. Ea permite accesul n citire/scriere. Constructorul cu parametri al clasei fstream: fstream(char *nume_fiier,int mod_deschid,int protec=filebuf::openprot); Modul de deschidere (mod_deschid) a unui fiier poate fi: ios::in fiier de intrare ios::out fiier de ieire ios::ate dup deschiderea fiierului, poziia curent este sfritul acestuia ios::app mod append (de scriere la sfritul unui fiier existent) ios::trunc dac fiierul exist, datele existente se pierd ios::nocreate dac fiierul asociat nu exist, nu va fi creat dect la scriere ios::binary fiier binar ios::noreplace fiierul nu trebuie s existe Modul de deschidere este definit printr-un cuvnt de stare, n care fiecare bit are o semnificaie particular. Pentru setarea (activarea) mai multor bii, se folosete operatorul | (sau logic, pe bit), ca n exemplu. class ios{ //.. public: enum open_mode{ in=0x01, out=0x02, ate=0x04, app=0x08, trunc=0x10, nocreate=0x20, noreplace=0x40, binary=0x80 }; };
216
Metoda open Prelucrarea unui fiier ncepe cu deschiderea acestuia, care se poate realiza: La instanierea obiectelor din clasele ifstream, ofstream sau fstream, cu ajutorul constructorului cu parametri (constructorul apeleaz automat funcia open); Prin apelul explicit al funciei open. Metoda open este definit n clasa fstreambase i este suprancrcat n funciile derivate din aceasta. Ea are aceeai parametri ca i constructorul clasei i prototipul: void open (char *nume_fiier, int mod_deschidere, int protecie); Metoda close realizeaz nchiderea unui fiier: void close();
Exerciiu: n exemplul urmtor se asociaz fluxului de ieire (obiectului fis_ies) fiierul numit text.txt. Se testeaz cuvntul de stare de eroare, iar dac nu au fost probleme la deschidere, n fiier se scrie un text (2 linii), apoi, o serie de constante numerice, formatate. Se nchide fiierul. Acelai fiier este asociat unui flux de intrare (pentru citire). Textul (scris anterior) este citit n variabila ir, apoi este afiat. Se citesc din fiier i apoi sunt afiate constantele numerice. Se nchide fiierul.
#include <fstream.h> #include <iomanip.h> int main() {ofstream fis_ies("text.txt"); //deschidere fiier text.txt if (!fis_ies){ cout<<"Eroare la dechiderea fiierului!\n"; return 1;} fis_ies<<"Scrierea unui text \n n fiier\n"; fis_ies<<100<<hex<<setw(10)<<100<<setw(20)<<setprecision(12); cout<<123.456789012356789<<endl; fis_ies.close(); //nchiderea fiierului ifstream fis_intr("text.txt"); //deschiderea fis. ptr. citire if (!fis_intr){cout<<"Eroare la deschiderea fis. ptr. citire!\n";return 1;} char sir[100]; for (int k=0; k<9; k++) {fis_intr>>sir; cout<<sir<<'\n';} cout<<endl; int i, j; double u; fis_intr>>i>>hex>>j>>u; cout<<i<<' '<<j<<' '<<u<<endl; fis_intr.close(); return 0; }
Exemplu: S se scrie un program care concateneaz dou fiiere, depunnd rezultatul n al treilea fiier. Se creaz trei fluxuri, f1, f2 i dest, care sunt ataate fiierelor corespunztoare (prin metoda open). Copierea n fiierul destinaie se realizeaz prin folosirea metodelor get, put i funcia copy. Metoda close ntrerupe legtura logic dintre fluxuri i fiiere.
#include <iostream.h> #include <process.h> #include <fstream.h> void semn_er(char *c) { cerr<<"\n\n Eroare la deschiderea fisierului "<<c<<endl;exit(1); void copiere(ofstream &dest, ifstream &sursa) {char C; while (dest && sursa.get(C)) dest.put(C); } void main() 217
CAPITOLUL 13 Intrri/ieiri {char nume_sursa1[14], nume_sursa2[14], destinatie[14]; ifstream f1, f2; ofstream dest; cout<<"Numele celor 3 fisiere:"<<"Destinatie Sursa1 Sursa2\n"; cin.read(destinatie,13);cin.read(nume_sursa1,13);cin.read(nume_sursa2,13); destinatie[13]=nume_sursa1[13]=nume_sursa2[13]='\0'; f1.open(nume_sursa1, ios::nocreate); if (!f1) semn_er(nume_sursa1); //utiliz operator ! redefinit f2.open(nume_sursa2, ios::nocreate); if (!f2) semn_er(nume_sursa2); //utiliz operator ! redefinit dest.open(destinatie); if (!dest) semn_er(destinatie); //utiliz operator ! redefinit copiere (dest, f1); copiere(dest, f2); f1.close();f2.close();dest.close(); }
// Deschide un alt fisier text si scrie in acesta niste numere (numerele sunt separate prin spatii)
fisierout.open("numere.txt"); fisierout <<15<<" "<<42<<" "<<1;fisierout.close();
// Deschide fisierul text numere.c pentru citirea numerelor intregi // Citeste numere din fisier pana cand ajunge la sfarsitul fisierului.
while (!fisierin.eof()) {fisierin >> numar; if (!fisierin.eof())
CAPITOLUL 13 Intrri/ieiri
nu exist un terminator de linie, trebuie specificat lungimea nregistrrii. Metodele write, read nu realizeaz nici o conversie.
Metoda write scrie n fiier un numr de n octei: ostream &write(const char * tab, int n); Metoda read citete din fiier n octei. istream &read (const char * tab, int n);
Limbajul C++ ofer (ca i limbajul C) posibilitatea de acces direct ntr-un fiier conectat la un flux de date. Dup fiecare operaie de citire (extragere din fluxul de intrare) sau citire (inserie n fluxul de ieire), pointerul care indic poziia curent n fluxul de date este incrementat cu un numr egal cu numrul de octei transferai. n aceast situaie se realizeaz un acces secvenial (ca n cazurile precedente). Clasele ifstream i ofstream au ca metode funciile seekg (membr a clasei istream), respectiv seekp (membr a clasei ostream) care permit modificarea valorii pointerului. istream & seekg(long); istream & seekg(long, seek_dir); ostream & seekp(long); ostream & seekp(long, seek_dir); Ambele metode primesc doi parametri: un ntreg reprezentnd deplasarea pointerului n raport cu baza (referina) precizat de al doilea parametru; o constant ntreag care precizeaz baza. Valorile constantei sunt definite n clasa ios:
class ios{ //. . . public: enum seek_dir{
deplasare fa de nceputul fiierului (implicit) deplasare fa de poziia curent deplasare fa de sfritul fiierului
Pentru aflarea valorii pointerului, clasa ifstream are metoda tellg, iar clasa ofstream are metoda tellp, cu prototipurile: long istream::tellg(); long ostream::tellp(); Exemplu: Se creaz ierarhia de clase din figura 13.5., n care se implementeaz clasa student i clasa proprie fisier_stud, clas class fstream derivat din fstream. n acelai fiier, binar, clase prietene se realizeaz i scrierea i citirea. Datorit posibilitii de acces direct, class fisier_stud class student se pot modifica informaiile referitoare la studentul nregistrat n fiier pe poziia k.
#include <fstream.h> #include <iomanip.h> class student { char nume[20]; int grupa, note[3]; public: void citire_date(); friend ostream &operator<<(ostream &, const student &); 219
CAPITOLUL 13 Intrri/ieiri friend class fisier_stud; }; class fisier_stud:public fstream //fiier binar cu obiecte din cls student {public: fisier_stud(){;}; fisier_stud(const char*num_f,int mod,int protecie=filebuf::openprot):fstream(num_f,mod |ios::binary,protecie){} void open(const char *num_f, int mod, int protectie=filebuf::openprot) {fstream::open(num_f,mod|ios::binary,protectie);}//apelul met. open din cls. fstream int citeste_f(student &); int scrie_f (const student &); }; void student::citire_date() { int gr, OK; for (int k=0; k<21; k++) nume[k]=0; cin.ignore(1000, '\n'); cout<<"Numele studentului:"; cin.get(nume, 21);cin.ignore(1000, '\n'); do{ cout<<"Grupa:"; cin>>gr; OK=(cin && gr>0 && gr<8000); if (!OK){ cout<<"Eroare. Repetai introducerea!\n"; cin.clear(); } else {grupa=gr; cin.ignore(1000, '\n');} }while (!OK); for (int k=0; k<3; k++){ int n; do{ cout<<"nota "<<k+1<<":"; cin>>n; OK=cin && n>0 && n<=10; if (!OK){ cout<<"Nota gresit.Repetati!\n";cin.clear();cin.ignore(1000, '\n'); } }while (!OK); note[k]=n;cin.ignore(1000, '\n'); } } ostream &operator << (ostream &ies, const student &stud) {ies<<"Student:"<<stud.nume<<" Grupa:"<<stud.grupa<<" Note:"; for (int k=0; k<3; k++) ies<<stud.note[k]<<' '; ies<<endl;return ies;} typedef union {student s; char sbin[sizeof(student)];} stud; int fisier_stud::scrie_f(const student &s) {stud s1; s1.s=s; write(s1.sbin, sizeof(student)); int fisier_stud::citeste_f(student &s) {stud s1; read(s1.sbin, sizeof(student)); return bad(); }
s=s1.s;
return bad();}
main() {char Nume_Fis[]="Stud_bin.bin"; student s; fisier_stud fs; int gata; //deschidere fiier ptr. scriere fs.open (Nume_Fis, ios::out); if (!fs){ cout<<"eroare la deschiderea fiierului "<<Nume_Fis<<" ptr. scriere\n"; return 1;} cout<<"Poz. n fi la deschidere:"<<fs.tellp()<<endl; gata=0; while(!gata) {char rasp; cout<<"Datele studentului:\n";s.citire_date();cout<<"Date introduse:"<<s<<endl; do{ 220
CAPITOLUL 13 Intrri/ieiri cout<<"Scriei date n fiier [D|N] ?"; rasp=toupper(cin.get());cin.ignore(1000, '\n'); } while (rsp!='D' && rsp!='N'); if (rsp == 'D'){ fs.scrie_f(s); cout<<"Poz. n fiier: "<<fs.tellp()<<endl;} do{ cout<<"Continuai introducerea [D|N]?";rsp=toupper(cin.get()); cin.ignore(1000, '\n'); } while (rsp!='D' && rsp!='N'); if (rsp=='N') gata=1; } fs.close();
//citire
fs.open(Nume_Fis, ios::in); if (!fs){ cout<<"Eroare la deschiderea fi-lui "<<Nume_Fis<<" ptr. citire\n"; return 1; } cout<<"Poz. n fi la deschidere:"<<fs.tellg()<<endl; cout<<"Date citite din fiier:\n"; int k=0; while (!fs.eof()) { fs.citete_f(s); if (!fs && !fs.eof()){ cout<<"Eroare la citire\n";return 1; } if (!fs.eof()){cout<<s<<endl;cout<<"Poz n fiier:"<<fs.tellg(); cout<<endl;k++;} } cout<<"S-au citit din fiier:"<<k<<" studeni\n"; fs.close(); fs.open(Nume_Fis, ios::in | ios::out); //deschidere fisier actualizare (intr/ies) if (!fs){ cout<<"Eroare la deschidere fis. "<<Nume_Fis<<" ptr. citire/ scriere\n"; return 1; } cout<<"Dai numrul stud-lui pentru care vrei s inlocuii datele:";cin>>k; cin.ignore(1000, '\n'); fs.seekg(k*sizeof(stud));s.citire_date();fs.scrie_f(s); fs.seekg(0); k=0; while(!fs.eof()){ fs.citire_f(s); if (!fs && !fs.eof()){cout<<"Eroare la citirea din fi:"<<Nume_Fis<<endl; return 1; } if (!fs.eof()){ cout<<s<<endl;cout<<"Poz n fiier:"<<fs.tellg()<<endl;k++;} } cout<<"S-au gasit n fiier:"<<k<<" studeni\n"; fs.close(); return 0; }
221
CAPITOLUL 13 Intrri/ieiri
Chestiuni practice
Rezolvai problemele din capitolul 8, folosind abordarea orientat pe obiecte.
222