Sunteți pe pagina 1din 17

CAPITOLUL 13

Intrri/ieiri

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

13

13.1. PRINCIPIILE DE BAZ ALE SISTEMULUI DE INTRRI/IERI DIN LIMBAJUL C++


n limbajul C++ exist dou sisteme de intrri/ieiri: Unul tradiional, motenit din limbajul C, n care operaiile de intrare/ieire se realizeaz cu ajutorul unor funcii din biblioteca standard a sistemului (vezi capitolul 8); Unul propriu limbajului C++, orientat pe obiecte. Sistemul de I/O orientat pe obiecte al limbajului C++ trateaz n aceeai manier operaiile de I/O care folosesc consola i operaiile care utilizeaz fiiere (perspective diferite asupra aceluiai mecanism). La baza sistemului de I/E din C++ se afl: dou ierarhii de clase care permit realizarea operaiilor de I/O; conceptul de stream (stream-ul este un concept abstract care nglobeaz orice flux de date de la o surs (canal de intrare) la o destinaie (canal de ieiere), la un consumator. Sursa poate fi tastatura (intrar ea standard), un fiier de pe disc sau o zon de memorie. Destinaia poate fi ecranul (ieirea standard), un fiier de pe disc sau o zon de memorie (figura 13.1). Fluxuri din clasa istream Memoria intern Fluxuri din clasa ostream

Fluxuri din clasa ifstream

fiiere

Fluxuri din clasa ofstream

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; Posibilitatea de a realiza operaii de I/O nu numai cu date de tipuri predefinite, ci i cu obiecte de tip abstract.

205

CAPITOLUL 13

Intrri/ieiri

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

CAPITOLUL 13

Intrri/ieiri

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

Zona tampon (buffer-ul) este interfaa dintre program i sistemul de operare.

buffer cin buffer cout

S urmrim cum se realizeaz transferul informaiei n cazul operaiilor multiple: cin>>a>>x>>ir;


cin>>a;

Figura 13.3. Rolul buffere-lor n operaiile de I/O

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 octe t 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.

13.2. TESTAREA I MODIFICAREA STRII UNUI FLUX


Clasa ios, clas de baz a ierahiei claselor de I/O, definete o mulime de tipuri, variabile i metode comune tuturor tipurilor de stream-uri. Starea unui stream (rezultatul ultimului acces la acesta) este pstrat n cuvntul de stare, care este dat membr a clasei ios. Fiecrei instanieri a unei clase de intrare/ieire i se asociaz propriul cuvnt de stare (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:

207

CAPITOLUL 13 int state; public:

Intrri/ieiri

//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

enum io_state{ goodbit=0x00, eofbit=0x01, failbit=0x02, badbit=0x04, hardbit=0x08 };


};

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

cout<<"Bit de eroare setat n cuvntul de stare!\n"; cin>>a;

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

208

CAPITOLUL 13

Intrri/ieiri

13.3. FORMATAREA DATELOR DIN FLUXURILE DE INTRARE/IEIRE


Unul dintre principalele avantaje oferite de sistemul de I/O din limbajul C++ l reprezint ignorarea aspectului formatrii, folosindu-se o formatare implicit. n plus, se permite definirea unei formatri specifice pentru o anumit aplicaie. Aa cum s -a subliniat n cazul cuvntului de eroare, cuvntul de format poate fi privit ca un ntreg, pentru care fiecare bit reprezint o constant predefinit din clasa ios. n cadrul acestui cuvnt sunt definite cmpuri de bii (cuvntul de format este dat membr care conine un numr de indici ce sunt bii individuali). class ios { // protected: long flag_x; int x_width; public: enum {skipws = 0x0001, left = 0x0002, right = 0x0004, internal = 0x0008, dec = 0x0010, oct = 0x0020, hex = 0x0040, showbase = 0x0080, showpoint = 0x0100, uppercase = 0x0200, showpos = 0x0400, scientific = 0x0800, fixed = 0x1000, unitbuf = 0x2000, stdio=0x4000 }; };

//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 basefield adjustfield

scientific

uppercase

showpoint

showbase

internal

unitbuf

showpos

fixed

right

hex

oct

Figura 13.4. Cmpurile de bii din cuvntul de stare 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.

209

dec

left

skipws

CAPITOLUL 13

Intrri/ieiri

13.3.1. FORMATAREA PRIN MANIPULATORI


Manipulatorii sunt funcii speciale, asemntoare operatorilor, care pot fi folosite mpreun cu operatorii de inserie ntr-un flux de ieire sau de extracie dintr-un flux de intrare, n scopul modificrii caracteristicilor formatului informaiilor de intrare/ieire. Manipulatorii furnizeaz, ca rezultat, fluxul obinut n urma aciunii manipulatorilor, ceea ce permite ca acetia s fie tratai ca informaii de transmis. Manipulatorii permit, deasemenea, nlnuirea operatorilor insertori sau extractori care utilizeaz formate diferite. Manipulatorii pot fi: Manipulatori fr parametri; Manipulatori cu parametri;

13.3.1.1. Manipulatori fr parametri


Prototipul manipulatorilor fr parametri este: ostream & nume_manipulator(ostream &); istream & nume_manipulator(istream &); Manipulatorii fr parametri (prezentai n tabelul 13.1.) se folosesc astfel: flux_ieire<<manipulator; flux_intrare>>manipulator; Tabelul 13.1 Manipula Intrare/ tor Ieire dec I/O hex I/O oct I/O ws I endl O ends O flush O Aciune Formateaz datele numerice n zecimal (activeaz bitul de conversie zecimal) Formateaz datele numerice n hexa (activeaz bitul de conversie hexazecimal) Formateaz datele numerice n octal (activeaz bitul de conversie octal) Ignor caracterele "spaii albe" (activeaz bitul de salt peste spaiile albe) Afieaz (insereaz) un caracter '\n' i elibereaz fluxul Insereaz un caracter null, de sfrit de flux (\0) Videaz (golete) buffer-ul, elibereaz fluxul

13.3.1.2. Manipulatori cu parametri


Prototipul manipulatorilor fr parametri (prezentai n tabelul 13.2.) este: istream & manipulator (argument); ostream & manipulator (argument); Tabelul 13.2. Manipulator setbase(int baza) resetiosflags(long f) setiosflags (long f) setfill (int c) setprecision (int p) setw (int w) Aciune Stabilete baza de conversie Atribuie valoarea 0 tuturor biilor indicai de argument, lsnd restul biilor nemodificai (dezactiveaz indicatorii specificai de f) Atribuie valoarea 1 tuturor biilor indicai de argument, lsnd restul biilor nemodificai (activeaz indicatorii specificai de f) Definete caracterul de umplere (cel implicit este spaiul liber, blank-ul) Definete precizia pentru numerele reale Definete limea cmpului (numrul de octei care vor fi citii sau afisai)
210

Intrare/ Ieire I/O I/O

I/O

I/O I/O I/O

CAPITOLUL 13

Intrri/ieiri

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


cout<<"x="<<setw(8)<<x<<endl; cout<<"x="<<setw(20)<<x<<endl;

//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
w=34; ab='34' & 0377; db=('34'>>8)&0377; cout<<"w="<<w<<" ab="<<ab<<" db="<<db<<endl; u=2579.75;v=12345.567E+10;

//w=34 ab=3 db=4

//formatare in octal si hexa


cout<<"a in baza 10="<<a<<" in octal="<<oct<<a<<" in hexa="<<hex<<a<<endl;

//a in baza 10=125 in octal=175 in hexa=7d


cout<<"b="<<dec<<b<<endl; }

//b=10

13.3.2. FORMATAREA PRIN METODE


Formatarea fluxurilor de intrare/ieire se poate realiza i prin metode ale clasei ios.

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 argumen t. Ea modific pe 0 toi biii din cmpul respectiv, dup care seteaz (pe 1) bitul respectiv. Exemple:
cout. setf (ios:: showpos | ios :: uppercase | ios:: internal)

//toi biii vor fi setai pe valoarea 1


cout.setf (ios :: hex, ios :: basefield) //seteaz indicele hex din cmpul basefield cout. setf (ios :: skipws | ios :: hex | ios:: showbase, ios :: basefield)

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 ('#').

211

CAPITOLUL 13

Intrri/ieiri

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.

13.4. METODELE CLASEI istream


Clasa istream este derivat din clasa ios: ios:istream. Supradefinirea operatorului de extracie >> 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.
212

CAPITOLUL 13

Intrri/ieiri

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

13.5. METODELE CLASEI ostream

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 afi a 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);
213

CAPITOLUL 13

Intrri/ieiri

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

13.6. MANIPULATORI CREAI DE UTILIZATOR


Manipulatorii sunt funcii speciale care pot fi utilizate alturi de operatorii de inserie/extracie pentru a formata datele de ieire/intrare. Pe lng manipulatorii predefini, utilizatorul i poate crea manipulatori proprii. Crearea manipulatorilor fr parametri ostream &nume_manipulator (ostream &); istream &nume_manipulator (istream &); Crearea manipulatorilor cu parametri Crearea manipulatorilor fr parametri necesit folosirea a dou funcii: ostream & nume_manipulator (ostream &, int); //pentru un flux de ieire //pentru un flux de intrare

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 $).

214

CAPITOLUL 13 Intrri/ieiri #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;}

13.7. FLUXURI DE DATE PENTRU FIIERE


Un flux de intrare/ieire poate fi asociat unui fiier. Pentru a asocia un flux de ieire unui fisier, este necesar crearea unui obiect de tipul ofstream. Clasa ofstream este derivat din clasele ostream (motenete metodele care permit inserarea informaiilor ntr-un flux de ieire) i fstreambase (motenete operaiile privitoare la asocierea fiierelor). Pentru a asocia un flux de intrare unui fiier, este necesar crearea unui obiect de tipul ifstream. Clasa ifstream este derivat din clasele istream (motenete metodele care permit extragerea informaiilor dintr-un flux de intrare) i fstreambase (motenete operaiile privitoare la asocierea fiierelor). Pentru crearea unor obiecte din clasele ifstream sau ofstream se impune includerea headere-lor iostream.h i fstream.h. Constructorii clasei ofstream sunt: ofstream(); Fluxul nu este asociat nici unui fiier ofstream(const char *nume_fisier, int mod_acces=ios:out); Parametri constructorului sunt numele fiierului i modul de acces la acesta (scriere, fiier de ieire). ofstream (int fd, char *buffer, int lung_buffer); Parametrii sunt numrul intern al fisierului (fd), zona tampon de intrri/ieiri (buffer) i lungimea zonei tampon (lung_buffer). Constructorii clasei ifstream sunt: ifstream(); 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(. . . );

215

CAPITOLUL 13

Intrri/ieiri if (fis_ies) . . .;

Pentru examinarea strii fluxului de eroare corespunztor:

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 }; }; Exemple: ifstream f1("DATE.txt", ios::in|ios::nocreate);
fstream f2("pers.dat", ios::in|ios::out);

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

216

CAPITOLUL 13

Intrri/ieiri

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

Observaii: Deschiderea i nchiderea fiierului s-ar fi putut realiza i astfel:


fstream fis_ies;fis_ies.open("text.txt", ios::out);fis_ies.close(); fstream fis_in;fis_in.open("text.txt", ios::in);fis_in.close();

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

217

CAPITOLUL 13

Intrri/ieiri

Exerciiu: Se ilustreaz folosirea fluxurilor pentru operaii de citire/scriere n fiiere text.


#include <fstream.h> #include <iostream.h> void main() { ofstream fisierout("nou.txt"); // Deschide fisierul text nou.txt.. fisierout << " Teste fisiere "; //Scrie un text in fisier fisierout.close(); // Inchide fisierul.

// 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 nou.txt pentru citire.


ifstream fisierin; fisierin.open("nou.txt"); char p[50]; // Stabileste o zona de memorie folosita pentru citirea textului. fisierin >>p; // Citeste si afiseaza primele doua cuvinte din fisier. cout <<p<<" "; fisierin >>p; cout <<p<<endl; fisierin.close(); // Inchide fisierul. int numar; fisierin.open("numere.c");

// 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()) } fisierin.close(); // Inchide fisierul.

// Citeste un numar intreg.


cout<<numar<<endl;

// Daca nu a ajuns la sfarsitul fisierului afiseaza numarul. // se citeste textul din fisierul nou.txt cuvant cu cuvant.
fisierin.open("nou.txt"); while (!fisierin.eof()) // Citeste cuvinte din fisier pana ajunge la sfarsitul fisierului. { // Citeste cuvant cu cuvant. fisierin >>p; cout <<p<<endl; } }

13.8. FIIERE BINARE


Fiierele binare reprezint o succesiune de octei, asupra crora la intrare sau la ieire nu se realizeaz nici o conversie. Ele sunt prelucrate binar, spre deosebire de exemplul anterior, n care prelucrarea se realiza n mod text (un numr n format intern este reprezentat binar, dar n format extern el apare ca un ir de caractere. Un ir n formatul extern are terminatorul '\n', iar n format intern are terminatorul '\0'). Deoarece 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);
218

CAPITOLUL 13

Intrri/ieiri

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{

beg=0, cur=1, end=2


}; };

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 implemenclass fstream teaz clasa student i clasa proprie fisier_stud, clas 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. Figura 13.5. Ierarhia de clase
#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 &); 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{ 219

CAPITOLUL 13 Intrri/ieiri 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{ 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); 220

CAPITOLUL 13 Intrri/ieiri 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; }

NTREBRI I EXERCIII Chestiuni teoretice


1. Ce nelegei prin conceptul de stream? 2. Care considerai c ar fi avantajele utilizrii abordrii orientate pe obiecte a sistemului de I/O? 3. Ce sunt manipulatorii? 4. Cum i poate crea utilizatorul manipulatorii proprii?

Chestiuni practice
Rezolvai problemele din capitolul 8, folosind abordarea orientat pe obiecte.

221