Cap. 5. Stream-uri
Cap. 5.1. Introducere
Stream-urile au in principal rolul de a abstractiza operatiile de intrare-
iesire. Ele ofera metode de scriere si citire a datelor independente de
dispozitivul I/O si chiar independente de platforma. Stream-urile incapsuleaza
(ascund) problemele specifice dispozitivului cu care se lucreaza, sub libraria
standard iostream.
Alt avantaj al folosirii stream-urilor se datoreaza implementarii
librariei iostream, care utilizeaza un sistem de buffer-e. Se stie ca in
general operatiile de intrare/iesire cu dispozitivele periferice sunt relativ
mari consumatoare de timp, astfel incat aplicatiile sunt uneori nevoite sa
astepte terminarea acestor operatiuni. Informatiile trimise catre un stream nu
sunt scrise imediat in dispozitivul in cauza, ci sunt transferate intr-o zona de
memorie tampon, din care sunt descarcate catre dispozitiv abia in momentul
umplerii acestei zone de memorie.
In C++ stream-urile au fost implementate utilizand clase, dupa cum
urmeaza:
clasa streambuf gestioneaza buffer-ele.
clasa ios este clasa de baza pentru clasele de stream-uri de
intrare si de iesire. Clasa ios are ca variabila membru un obiect de
tip streambuf.
clasele istream si ostream sunt derivate din ios.
clasa iostream este derivata din istream si ostream
si ofera metode pentru lucrul cu terminalul.
clasa fstream ofera metode pentru operatii cu fisiere.
Cap. 5.2. Obiecte standard
Cand un program C++ care include iostream.h este lansat in
executie, sunt create si initializate automat patru obiecte:
cin gestioneaza intrarea de la
intrarea standard (tastatura).
cout gestioneaza iesirea catre iesirea
standard (ecranul).
cerr gestioneaza iesirea catre
dispozitivul standard de eroare (ecranul), neutilizand buffer-e.
clog gestioneaza iesirea catre
dispozitivul standard de eroare (ecranul), utilizand buffer-e.
Cap. 5.3. Redirectari
Dispozitivele standard de intrare, iesire si eroare pot fi
redirectate catre alte dispozitive. Erorile sunt de obicei redirectate
catre fisiere, iar intrarea si iesirea pot fi conduse ("piped")
catre fisiere utilizand comenzi ale sistemului de operare (utilizarea iesirii
unui program ca intrare pentru altul).
Sintaxa pentru operatii de iesire, cout:
cout << InformatieDeTrimisLaIesire;
respectiv pentru intrare, cin:
cin >> NumeVariabila;
De fapt, cin si cout sunt niste obiecte definite global,
care au supraincarcat operatorul >> respectiv << de mai multe ori,
pentru fiecare tip de parametru in parte (int, char *, etc.):
istream &operator >> (TipParametru &)
De exemplu:
#include <iostream.h>
void main()
{
int IntegerNumber;
cout << "IntegerNumber = ";
cin >> IntegerNumber;
cout << "\nWhat you entered = " << IntegerNumber << endl;
}
Acest scurt program citeste de la intrarea standard o valoare intreaga,
pe care o trimite apoi catre iesirea standard. Se observa posibilitatea de a
utiliza simbolurile '\n', '\t', s.a.m.d (ca la printf,
scanf, etc.). Utilizarea simbolului endl va forta golirea zonei
tampon, adica trimiterea datelor imediat catre iesire.
Atat operatorul >> cat si << returneaza o referinta catre
un obiect al clasei istream. Deoarece cin respectiv cout
este si el un obiect istream, valoarea returnata de o operatie de
citire/scriere din/in stream poate fi utilizata ca intrare/iesire pentru
urmatoarea operatie de acelasi fel.
Cap. 5.4. cin
Functia cin.get()
Functia membra get() poate fi utilizata pentru a obtine un singur
caracter din intrare, apeland-o fara nici un parametru, caz in care returneaza
valoarea utilizata, sau ca referinta la un caracter.
get() fara parametri
In aceasta forma, functia intoarce valoarea caracterului gasit. De
remarcat este faptul ca, spre deosebire de operatorul >>, nu poate fi
utilizata pentru a citi mai multe intrari, deoarece valoarea returnata este de
tip intreg, nu un obiect istream. Mai jos, un exemplu de utilizare:
#include <iostream.h>
void main()
{
char c;
while((c = cin.get()) != EOF)
{
cout << "c = " << c << endl;
}
}
Citirea de siruri de caractere utilizand get()
Operatorul >> nu poate fi utilizat pentru a citi corect siruri de
caractere de la intrare deoarece spatiile sunt interpretate ca separator intre
diverse valori de intrare. In astfel de cazuri trebuie folosita functia get().
Sintaxa de utilizare a functiei get in acest caz este urmatoarea:
cin.get(char *PointerLaSirulDeCaractere, int LungimeMaxima, char Sfarsit);
Primul parametru este un pointer la zona de memorie in care va fi depus
sirul de caractere. Al doilea parametru reprezinta numarul maxim de caractere ce
poate fi citit plus unu. Cel de-al treilea parametru este caracterul de
incheiere a citirii, care este optional (implicit considerat '\n').
In cazul in care caracterul de incheiere este intalnit inainte de a fi
citit numarul maxim de caractere, acest caracter nu va fi extras din stream.
Exista o functie similara functiei get(), cu aceeasi sintaxa, numita
getline(). Functionarea sa este identica cu get(), cu exceptia
faptului ca acel ultim caracter mentionat mai sus este si el extras din stream.
Functia cin.ignore()
Aceasta functie se utilizeaza pentru a trece peste un numar de
caractere pana la intalnirea unui anume caracter. Sintaxa sa este:
cin.ignore(int NumarMaximDeCaractere, char Sfarsit);
Primul parametru reprezinta numarul maxim de caractere ce vor fi
ignorate iar al doilea parametru caracterul care trebuie gasit.
Functia cin.peek()
Aceasta functie returneaza urmatorul caracter din stream, fara insa a-l
extrage.
Functia cin.putback()
Aceasta functie insereaza in stream un caracter.
Cap. 5.5. cout
Cap. 5.5.1. Functii membre ale cout
Functia cout.flush()
Functia cout.flush() determina trimiterii catre iesire a tuturor
informatiilor aflate in zona de memorie tampon. Aceasta functie poate fi apelata
si in forma cout << flush.
Functia cout.put()
Functia cout.put() scrie un caracter catre iesire. Sintaxa sa
este urmatoarea:
cout.put(char Caracter);
Deoarece aceasta functie returneaza o referinta de tip ostream,
pot fi utilizate apeluri succesive ale acesteia, ca in exemplul de mai jos:
#include <iostream.h>
void main()
{
cout.put('H').put('i').put('!').put('\n');
}
Functia cout.write()
Aceasta functie are acelasi rol ca si operatorul <<, cu exceptia
faptului ca se poate specifica numarul maxim de caractere ce se doresc scrise.
Sintaxa functiei cout.write() este:
cout.write(char *SirDeCaractere, int CaractereDeScris);
Cap. 5.5.2. Formatarea iesirii
Functia cout.width()
Aceasta functie permite modificarea dimensiunii valorii trimise spre
iesire, care implicit este considerata exact marimea campului in cauza. Ea
modifica dimensiunea numai pentru urmatoarea operatie de iesire. Sintaxa este:
cout.width(int Dimensiune);
Functia cout.fill()
Functia cout.fill() permite modificarea caracterului utilizat
pentru umplerea eventualului spatiu liber creat prin utilizarea unui dimensiuni
mai mari decat cea necesara iesirii, cu functia cout.width(). Sintaxa
acesteia este:
cout.fill(char Caracter);
Cap. 5.5.3. Optiuni de formatare a iesirii
Pentru formatarea iesirii sunt definite doua functii membre ale cout,
si anume:
Functia cout.setf()
Aceasta functie activeaza o optiune de formatare a iesirii, primita ca
parametru:
cout.setf(ios::Optiune);
Unde Optiune poate fi:
showpos determina adaugarea semnului plus (+) in fata
valorilor numerice pozitive;
left, right, internal schimba alinierea iesirii;
dec, oct, hex schimba baza de numeratie pentru
valori numerice;
showbase determina adaugarea identificatorului bazei de
numeratie in fata valorilor numerice.
Functia cout.setw()
Aceasta functie modifica dimensiunea iesirii, fiind similara functiei
cout.width(). Sintaxa sa este:
cout.setw(int Dimensiune);
In continuare vom exemplifica utilizarea functiilor pentru formatarea
iesirii:
#include <iostream.h>
#include <iomanip.h>
void main()
{
int number = 783;
cout << "number = " << number;
cout.setf(ios::showbase);
cout << "number in hexa = " << hex << number;
cout.setf(ios::left);
cout << "number in octal, aligned to the left = " << oct << number;
}
Cap. 5.6. Operatii de intrare/iesire cu fisiere
Lucrul cu fisiere se face prin intermediul clasei ifstream pentru
citire respectiv ofstream pentru scriere. Pentru a le utiliza,
aplicatiile trebuie sa includa fstream.h. Clasele ofstream si
ifstream sunt derivate din clasa iostream, ca urmare toti
operatorii si toate functiile descrise mai sus sunt mostenite si de aceasta
clasa.
Sintaxele pentru constructorii acestor doua clase sunt:
ofstream Variabila(char *NumeFisier, ios::Mod);
ifstream Variabila(char *NumeFisier);
Acesti constructori au rolul de a deschide fisierul specificat ca
parametru. Cel de-al doilea parametru al constructorului ofstream este
optional si specifica modul de deschidere a fisierului:
ios::append - adauga la sfarsitul fisierului;
ios::atend - pozitioneaza pointer-ul la sfarsitul fisierului, insa
informatiile pot fi scrise oriunde in cadrul fisierului;
ios::truncate - este modul de deschide implicit: vechiul continut
al fisierului este pierdut;
ios::nocreate - daca fisierul nu exista, atunci operatia
esueaza;
ios::noreplace - daca fisierul deja exista, atunci operatia
esueaza.
Pot fi utilizate prescurtarile: app pentru append, ate
pentru atend, si trunc pentru truncate.
Pentru a inchide aceste fisiere trebuie apelata functia membra
close().
Rezultatul operatiilor de intrare/iesire poate fi testat prin
intermediul a patru functii membre:
eof() verifica daca s-a ajuns la sfarsitul fisierului;
bad() verifica daca s-a executat o operatie invalida;
fail() verifica daca ultima operatie a esuat;
good() verifica daca toate cele trei rezultate precedente sunt
false.
In urmatorul capitol veti afla despre mecanismul de tratare a exceptiilor
oferit de C++.
Realizat de Dragos Acostachioaie, ©1998
http://www.biosfarm.ro/~dragos