|
Politica de confidentialitate |
|
• domnisoara hus • legume • istoria unui galban • metanol • recapitulare • profitul • caract • comentariu liric • radiolocatia • praslea cel voinic si merele da aur | |
Sistemul de intrare/iesire din C++ | ||||||
|
||||||
Pe langa faptul ca poate fi folosit sistemul de intrare/iesire (I/O)
din C, in C++ mai este definit inca un sistem complet integrat,
care permite operarea cu obiecte de tipuri definite de utilizatori. Ca si sistemul
I/O din C, cel din C++ opereaza prin streamuri (fluxuri). Un stream este o entitate
logica in care se intoduc (se insereaza) sau se extrag informatii. Toate
streamurile se comporta in mod asemanator, chiar daca echipamentele fizice
la care sunt conectate pot sa difere substantial. u3p13pm cin Intrare standard Tastatura cout Iesire standard Ecran cerr Iesire standard pentru eroare Ecran clog Versiune cu buffer de memorie pentru cerr Ecran Streamurile cin, cout si cerr corespund streamurilor stdin, stdout si stderr din C. 6.1 Functii de I/O pentru tipurile predefinite Operatiile de I/O din C++ se efectueaza folosind functiile operator de insertie
<< si operator de extragere >>. Streamurile pot fi considerate ca
recipienti de caractere aranjate intr-o anumita ordine in care se
introduc si din carte se extrag date. Functiile de operare asupra streamurilor
specifica modul in care se executa conversia intre un sir de caractere
din stream si o variabila de un anumit tip. Aceste functii operator sunt definite
in clasa ostream, respectiv istream, pentru toate tipurile predefinite
ale limbajului, iar pentru tipurile definite de utilizator ele pot fi supraincarcate.
class ostream : public virtual ios A class istream : public virtual ios A ? Exemplul 6.1 Functia de citire de la consola a unei secvente de numere intregi separate prin spatii albe (whitespace adica unul din caracterele blanc, tab, newline, carriage return, formfeed) poate arata asfel: void fint()A int size = 10; int arraya10i; for(int i=0;i<size;i++)A if (cin >> arrayaii) cout << arrayaii << " "; else A cout << "eroare non-int"; break; O intrare diferita de intreg va cauza eroare in operatia de citire
si deci oprirea buclei for. De exemplu, din intrarea: O alta solutie pentru citirea unei secvente de intrare este prin folosirea uneia din functiile get() definite in clasa iostream astfel: class iostream : public virtual ios A void fg()A char c; void fg()A char c; Functia cu trei argumente istream::get() citeste cel mult n-;1 caractere intr-un tablou de caractere care incepe la adresa p si introduce, ca ultim caracter in tablou, caracterul 0. Cel de-al treilea argument specifica caracterul terminator al citirii, implicit caracterul newline (‘\n’), care este lasat ca primul caracter necitit in stream. O utilizare tipica a functiei get() cu trei argumente este citirea unei linii de intrare intr-un buffer de dimensiune fixa, pentru o analiza ulterioara. De exemplu: void fbuf()A char bufa100i; cin >> buf; // operatie suspecta, pot apare erori cin.get(buf,100,'\n'); // citire sigura Functiile de I/O pentru tipuri definite de utilizator se obtin prin supraincarcarea operatorilor de insertie si de extragere, care au urmatoarea forma generala: ostream& operator<<(ostream& os,tip_clasa nume)A Primul argument al functiei este o referinta la streamul de iesire, respectiv
de intrare. Pentru functia operator de extragere << al doilea argument
este dat printr-o referinta la obiectul care trebuie sa fie extras din stream;
in aceasta referinta sunt inscrise datele extrase din streamul de
intrare. Pentru functia operator de insertie >> al doilea argument este
dat prin tipul si numele obiectului care trebuie sa fie inserat, sau printr-o
referinta la acesta. Functiile operator de insertie si extractie returneaza
o referinta la streamul pentru care au fost apelate, astfel incat
o alta operatie de I/O poate fi adaugata acestuia. class StringA char *str; int size; public: ? Exemplul 6.2 Fie functia fc() in care se citesc de la consola un numar complex (de tip Complex) si un sir (de tip String) care apoi sunt afisate pe ecran. void fc()A for (int i=0;i<size;i++) cout << bufaii; cout << endl; Executia acestei functii produce urmatoarele mesaje la consola: Introduceti x, y: 1.3 4.5 z = (1.3,4.5) ? Functia operator de extragere a clasei String permite citirea sigura a unor siruri de caractere de o dimensiune maxima impusa (255 de caractere in exemplul dat). Extragerea unor siruri de o dimensiune oarecare este lasata ca un exercitiu simplu pentru cititor. 6.3 Starea streamurilorFiecare stream (istream sau ostream) are asociata o stare, memorata intr-un intreg in clasa ios, iar conditiile nestandard sau erorile aparute in operatiile cu acesta pot fi setate sau testate folosind operatii publice ale clasei de baza ios. Valorile folosite pentru descrierea starii unui stream si functiile de testare a starii definite in clasa de baza ios sunt urmatoarele: class ios A S; int rdstate() const; int good() const; int eof() const; int fail() const; int bad() const; // …….. S; Functia rdstate() returneaza 0 daca nu a aparut nici o eroare si nici nu a
a fost intalnit indicatorul de sfarsit al streamului (end
of file, eof). Fiecare stare in parte poate fi obtinuta si prin apelul
uneia din functiile good(), eof(), fail() sau bad(). In exemplele prezentate pana acum au fost folosite operatii de
I/O neformatate, in care transformarea unui obiect intr-o secventa
de caractere a fost executata conform unor reguli implicite. In C++ se
pot specifica formate diferite de cele implicite pentru operatiile de intrare
si de iesire, in mod asemanator cu formatele introduse prin functiile
printf() si scanf() din C. 6.5.1 Formatarea I/O folosind membrii clasei ios Clasa ios controleaza conexiunea dintre un stream si bufferul utilizat pentru operatiile de intrare si de iesire, avand astfel posibiltatea de specifica modul in care sunt introduse sau extrase caracterele. Clasa ios contine date membre care memoreaza informatii despre baza de numeratie folosita (zecimal, octal, hexazecimal), depre precizia cu care se scriu sau se citesc numerele in virgula mobila, etc, precum si functii care permit setarea sau examinarea acestora pentru fiecare stream. Flagurile (indicatorii) de formatare din clasa ios si functiile de acces la acestia sunt: class ios A public: char fill(char); // caracter de umplere char fill() const; long flags(long f); long flags() const; long setf(long); // setare indicatori long setf(long setbits, long field); long unsetf(long); int precision(int); // prec. nr. v. mobila int precision() const; Functia setf() cu un singur argument este utilizata pentru activarea unuia
sau mai multor indicatori de formatare. Fiind o functie membra a clasei ios,
ea trebuie sa fie apelata pentru un anumit obiect (stream), ceea ce inseamna
ca nu exista o stare globala de formatare, ci fiecare stream are propria lui
stare. Indicatorii de formatare pot fi modificati individual, prin apeluri separate
ale functiei setf() sau grupati intr-o expresie logica OR (SAU). De exemplu,
instructiunile: cout.setf(ios::hex); cout.setf(ios::showbase); sunt echivalente cu instructiunea: cout.setf(ios::hex | ios::showbase); si au ca efect afisarea unui numar in format hexazecimal, cu reprezentarea
explicita a bazei folosite. Dupa o astfel de formatare, instructiunea: cout << 100; va afisa la consola: 0x64. cout.setf(ios::oct, ios::basefield); // octal cout.setf(ios::dec, ios::basefield); // zecimal cout.setf(ios::hex, ios::basefield); // hexazecimal seteaza baza de numeratie fara efecte asupra altor parti ale starii streamului. Functia unsetf() este complementara functiei setf() si are ca efect stergerea unuia sau mai multor indicatori de format. Functia unset() opereaza intr-un mod asemanator cu functia setf(). ? Exemplul 6.3 Fie urmatoarea functie care formateaza streamuri folosind functiile membre ale clasei ios. void ff()A cout.setf(ios::uppercase | ios::scientific); cout <<100.12 <<’\n’; cout.unsetf(ios::uppercase); cout <<100.12 <<’\n’; La executia acestei functii se afiseaza la consola numarul 100.12 in urmatoarele formate, stabilite folosind functiile setf() si unsetf(): 1.0012E+002 Functia flags() permite examinarea starii indicatorilor de format, fara ca acestia sa fie modificati. Functia flags() returneaza o data de tipul long, care contine valoarea fiecarui indicator de format intr-un bit aflat pe pozitia corespunzatoare definirii din clasa ios. Functia width() specifica o marime de camp minim pentru reprezentarea
unui numar. Dupa apelul functiei width(w), daca valoarea inserata in stream
foloseste mai putin de w caractere, atunci se completeaza campul pana
la aceasta lungime cu caracterul de completare curent (implicit spatiu). Daca
pentru reprezentarea valorii inserate in stream sunt necesare mai mult
de w caractere, nu se trunchiaza numarul, ci se intoduc toate caracterele acestuia,
chiar daca se depaseste valoarea w. Functia precision() este utilizata pentru a determina numarul de cifre care sa fie afisate dupa punctul zecimal. ? Exemplul 6.4 Se considera urmatorul program care permite afisarea starii indicatorilor de formatare ai unui stream: void showflags()A long f, i, j; char indica15ia12i = A S; // se citeste starea indicatorilor f = cout.flags(); if (f) for (i=1,j=0; i<=0x2000; i = i<<1,j++)A if(i & f) cout << "Este activat " << indicaji << "\n"; S else cout<< "Nu este activat nici un indicator \n"; S void main()A cout << 1234.56 <<endl; showflags(); cout.setf(ios::right| ios::showpoint | ios::fixed); cout.fill('*'); cout.width(20); cout << 1234.56 << "\n"; showflags(); cout.unsetf(ios::right|ios::showpoint|ios::fixed); cout << 1234.56 <<endl; showflags(); S La executia acestui program se obtin urmatoarele mesaje la consola: 1234.56 Aceste mesaje evidentiaza corespondenta dintre comanda de formatare apelata,
numele indicatorilor de formatare modificati si efectul acestora asupra modului
de afisare a unor date. De asemenea, folosind aceasta functie se pot experimenta
si alte comenzi de formatare a streamurilor. ? A doua posibilitate de a modifica modul de formatare ai unui stream este aceea de a folosi functiile speciale numite manipulatori. O parte din manipulatorii care se pot folosi pentru formatarea streamurilor sunt prezentati in tabelul de mai jos: Manipulator Scop Intrare/Iesire dec Intrare/iesire de date in zecimal Intrare si iesire endl Insereaza un caracter newline Iesire ends Insereaza un null Iesire flush Goleste un stream Iesire hex Intrare/iesire in hexazecimal Intrare si iesire oct Intrare/iesire in octal Intrare si iesire resetiosflags(long f) Dezactiveaza indicatorii f Intrare si iesire setbase(int base) Seteaza baza numerica Iesire setfill(int ch) Seteaza caracterul de completare Iesire setiosflags(long f) Activeaza indicatorii f Intrare si iesire setprecision(int p) Stabileste nr. de cifre pt. precizie Iesire setw(int w) Stabileste dim. min. a campului Iesirews Omite spatii libere de la inceput Intrare Din acest tabel se poate observa ca cei mai multi manipulatori dubleaza functiile de formatare din clasa ios. ? Exemplul 6.5 Folosind aceeasi functie showflags() din exemplul precedent, se poate observa modul de formatare a streamurilor folosind manipulatori si corespondenta dintre acestia si functiile de formatare membre ale clasei ios. Executia functiei: void fm()A cout<<1234.56<<endl; showflags(); long flags=ios::right| ios::showpoint | ios::fixed; cout <<setw(20)<<setfill('*') <<setiosflags(flags); cout << 1234.56<<endl; showflags(); cout << resetiosflags(flags); cout << 1234.56; showflags(); Pentru accesul la manipulatorii care au argumente (cum sunt setw(), setfill(), etc.), este necesara includerea fisierului antet iomanip.h. 6.5 Sistemul I/O cu fisiere in C++ Desi biblioteca de streamuri din C++ reprezinta un sistem integrat pentru
operatiile de intrare/iesire, lucrul cu fisiere pe disc prezinta unele particularitati
care trebuie sa fie studiate separat. 6.5.1 Deschiderea si inchiderea fisierelor Pentru utilizarea unui fisier pe disc acesta trebuie sa fie asociat unui stream. Pentru aceasta se creaza mai intai un stream, iar apelul functiei open() a streamului executa asocierea acestuia cu un fisier ale carui caracteristici se transmit ca argumente ale functiei open(). Functia open() este functie membra a fiecareia dintre cele trei clase stream (ifstream, ofstream si fstream) si are prototipul: void open(const char *file_name, int mode, int access=filebuf::openprot); In acest prototip, file_name este numele fisierului, care poate include calea de acces. Argumentul mode defineste modurile in care poate fi deschis un fisier si are valorile definite in clasa de baza ios astfel: class iosA public: Argumentul mode este optional pentru streamuri de intrare ifstream, pentru
care valoarea implicita este ios::in, si pentru streamuri de iesire ofstream,
pentru care valoarea implicita este ios::out. Pentru streamuri de intrare/iesire
fstream, argumentul mode trebuie sa aiba una din valorile definite in
clasa ios. In argumentul mode se pot combina prin operatorul OR (SAU)
doua sau mai multe din aceste valori definite. ifstream input; input.open("intrare.txt"); ofstream output; output.open("iesire.txt"); fstream inout; inout.open("fisier", ios::in|ios::out); Dupa executia unei functii de deschidere open(), starea streamului este zero,
daca deschiderea s-a efectuat cu succes, si diferita de zero, daca nu s-a putut
efectua deschiderea fisierului. Pentru inchiderea unui fisier se apeleaza functia close(), care functie membra a claselor stream (ifstream, ofstream si fstream). Pentru scrierea si citirea dintr-un fisier de tip text se folosesc functiile operator << si >> ale streamului asociat acelui fisier. Aceste functii operator supraincarcate pentru un anumit tip de date pot fi folosite fara nici o modificare atat pentru a scrie sau citi de la consola cat si pentru a scrie sau citi dintr-un fisier pe disc. Acest lucru este posibil deoarece clasele ifstream, ofstream si fstream sunt derivate din clasele istream, ostream si iostream respectiv, iar conversia de la un tip derivat (de exemplu, ifstream) la un tip de baza al acestuia (de exemplu, istream) este implicita. Exemplul urmator evidentiaza acest mod de operare. ? Exemplul 6.6 Programul care urmeaza creaza un fisier de inventariere “inventar.txt” care contine numele articolului, pretul unitar, numarul de bucati si valoarea totala. void finv()A ofstream output("inventar.txt"); if (!output) cout << "Nu se poate deschide fisierul inventar.txt\n"; char buffera80i; double pret,total; int buc; S output.close(); S ? La citirea dintr-un fisier de tip text de pe disk folosind operatorul >> apar, la fel ca la citirea de la consola, anumite modificari de caractere. Pentru a evita astfel de modificari se folosesc functiile de I/O binare care vor fi prezentate in sectiunea urmatoare. 6.5.2 Operatii I/O binare cu fisiere 6.5.3 Accesul aleator la fisierePentru accesul aleator la date in fisiere pe disc, sistemul I/O din C++ foloseste doi pointeri asociati fiecarui fisier: pointerul de citire (get) care specifica pozitia de unde va avea loc urmatoarea citire din fisier si pointerul de scriere (put), care specifica pozitia unde va avea loc urmatoarea scriere in fisier. Pozitia intr-un fisier este pozitia unui caracter in fisierul respectiv are valori incepand de la valoarea zero, pana la valoarea maxima a numarului de caractere continute in fisier. Dupa fiecare operatie de citire sau se scriere, pointerul corespunzator este avansat secvential in fisier in mod automat. Se poate considera un fisier ca un tablou de caractere, accesate secvential (in mod automat) sau aleator (prin modificarea pointerilor de scriere si de citire). Pentru pozitionarea intr-o pozitie dorita a unuia dintre acesti pointeri se folosesc functii membre publice ale claselor de baza istream, ostream. Pentru accesul aleator in operatiile de iesire se pot folosi urmatoarele functii membre publice ale clasei ostream: class ostream: public virtual ios A Tipurile de date streamoff si streampos sunt definite in fisierul antet iostream.h, si au capacitatea de a contine cea mai mare valoare valida pe care o poate avea dimensiunea, respectiv offsetul intr-un fisier, iar seek_dir este o enumerare in clasa ios care poate lua urmatoarele valori: class ios A Functia seekp() cu un argument pozitioneaza pointerul de insertie a fisierului
la valoarea pos, data ca argument. Pentru accesul aleator in operatiile de intrare se pot folosi urmatoarele functii membre publice ale clasei istream: class istream : public virtual iosA Functiile supraincarcate seekg() cu unul si doua argumente se comporta
in mod asemanator cu functiile seekp(), dar opereaza asupra pointerului
de citire: functia seekg() cu un argument seteaza pointerul de citire in
pozitia pos transmisa ca argument; functia seekg() cu doua argumente deplaseaza
pointerul de citire al fisierului asociat streamului cu un numar de caractere
egal cu valoarea offset fata de originea orig specificata ca argument. In exemplele urmatoare se ilustreaza modul de utilizare a acestor functii de acces aleator la datele din fisiere. ? Exemplul 6.7 In functia finvers() se utilizeaza operatiile de acces aleator pentru inversarea primelor n caractere din fisierul cu numele “fisier.txt” . int finvers(int n)A long i, j; char c1, c2; fstream fisier("fisier.txt", ios::in|ios::out|ios::binary); for(i=0;i<n;i++)A fisier.get(c1); cout<< c1; for (i=0,j=n-1; i<j; i++,j--)A fisier.seekg(i, ios::beg); fisier.get(c1); fisier.seekg(j, ios::beg); fisier.get(c2); fisier.seekp(i, ios::beg); fisier.put(c2); fisier.seekp(j, ios::beg); fisier.put(c1); fisier.close(); return 0; Se presupune un fisier care contine urmatoarele caractere: 1234567890abcd... La apelul functiei finvers(10), la consola sunt afisate continutul primelor 10 pozitii din fisier inainte si dupa inversare astfel: 1234567890 La un nou apel al functiei finvers(10), mesajele afisate la consola sunt: 0987654321 6.6 Streamuri asociate cu siruri de caractere Asa cum s-a prezentat in sectiunea precedenta, un stream poate fi asociat cu un fisier pe disc. In mod asemanator, se poate asocia un stream cu un sir de caractere in memoria principala. Clasele care construiesc streamuri in memorie (deci asociate cu siruri de caractere stocate in memoria principala) sunt descrise de clasele istrstream, ostrstream si strstream, derivate din clasele istream, ostream, iostream si sunt definite in fisierul antet strstrea.h. Un stream de I/O asociat unui sir de caractere in memorie se poate construi ca un obiect din clasa strstream, care are doi constructori: strstream(); strstream(char* pch, int length, int mode); Constructorul implicit construieste un stream care foloseste un buffer intern
dinamic, care initial este gol. Fie functia: void fstr()A char* p = new chara100i; strstream ost(p, 100); ost << "123456789"; ost << "abcdef" << ends; cout << p; In aceasta functie se creaza un stream ost asociat unui tablou de caractere in memorie in care se introduc mai multe caractere, ultimul fiind un caracter nul. Caracterele introduse in streamul asociat cu tabloul de caractere p sunt afisate la consola prin apelul operatorului << , iar mesajul care se obtine la executia acestei functii este: 123456789abcdef. Din cele prezentate in acest capitol se poate intelege care este
ierarhia de clase care definesc streamurile C++. In Fig. 6.1. este prezentata
aceasta ierarhie. Clasa de baza ios este mostenita virtual in cele doua
clase istream si ostream. |
||||||
|
||||||
|
||||||
Copyright© 2005 - 2024 | Trimite document | Harta site | Adauga in favorite |
|