tratarea exceptiilor.spatii de nume. i/o
DESCRIPTION
Tratarea Exceptiilor.Spatii de nume. I/O. Curs 12-13 . Tratarea erorilor. C : int printf ( const char * format, ... ); Return Value: On success , the total number of characters written is returned. On failure , a negative number is returned. - PowerPoint PPT PresentationTRANSCRIPT
Tratarea Exceptiilor.Spatii de nume. I/O
Curs 12-13
Tratarea erorilor
• C :– int printf ( const char * format, ... ); – Return Value:
– On success, the total number of characters written is returned.
On failure, a negative number is returned. – Rareori programatorii verifica codul de retur– In cazul in care o fac, codul este o succesiune de if-uri care verifica variatele
posibilitati
– Problema majora – cuplarea – dependenta – gradul in care un modul depinde de un alt modul
Tratarea erorilor in C
1. Valoare de retur care indica o problema
2. Setarea unui flag care sa indice existenta unei erori : errno, perror()– errno – variabila intreaga declarata in <errno.h>, folosita de
numeroase functii pentru a returna coduri de eroare– void perror ( const char * str ) (print error message)– Interpreteaza valoare lui errno si o converteste la un string pe
care il afiseaza pe stderr (de obicei ecran)– perror () trebuie apelata chiar dupa aparitia erorii, altfel poate fi
suprascrisa de alte functii
3. Folosirea setjmp() si longjmp()– setjmp() salveaza o stare normala a programului– In situatii de eroare se apeleaza longjmp() care restaureaza
acea stare buna– NU apeleaza DESTRUCTORII!!! (folosit in C++)
Tratarea erorilor CErrno+perror
#include <stdio.h>#include <errno.h>
int main (){ FILE * pFile; pFile=fopen ("unexist.txt","rb"); if (pFile==NULL){ printf("errno = %d\n", errno); perror ("The following error occurred"); } else fclose (pFile); return 0;}
Cod de retur
char *c = new char[200000000]if ( c == NULL ) cout<<“eroare"; else{ //procesare informatii …
delete c; }
Sabloane GRASP• GRASP – General Responsibility Assignment Patterns (Principles)
• Low coupling – dezvoltarea de module independente
– dependenta scazuta intre module,
– modificari asupra unui modul sa nu determine modificari majore asupra altor module
• High Cohesion
– un modul trebuie sa aiba o multime de responsabilitati relationate
– Utilizarea claselor oera suport pentru coeziunea unui proiect
• Controller
– Delegarea sarcinilor de tratare a evenimentelor din interfata grafica unei clase cu rol de tratare a evenimntelor
• Polimorfism – variatiile comportamentelor pe baza tipurilor de date sunt tratate de tipul de date, folosind apeluri polimorfice
Tratarea erorilor in C
• Codul de tratare a erorilor este puternic cuplat cu codul logicii aplicatiei
• La apelul unei functii care returneaza un cod de eroare, inconjuram codul care face apelul de cod de testare a modului de finalizare a apelului
• NULL si -1 (valori negative) folosite pentru a indica esecul unui apel – trebuie testate imediat dupa apel
• La folosirea setjmp si longjmp exista o puternica cuplare intre codul unde se slaveaza starea normala si codul in care apare eroarea
Abordarea C++
• Tratarea exceptiilor:• Codul de tratare a erorilor este separat de codul care trateaza logica
aplicatiei– Intai scriem codul care dorim sa se execute, apoi separat, se scrie codul
care se ocupa de tratarea situatiilor neprevazute
– Daca se fac apeluri multiple ale aceleiasi functii, erorile returnate de acea functie sunt tratate o singura data, intr-un singur loc
• Erorile nu mai pot fi ignorate.– Daca o functie trebuie sa transmita un mesaj de eroare apelantului,
acea functie va arunca (throw) un obiect reprezentand eroarea in afara functiei.
– Daca apelantul nu prinde (catch) eroarea si nu o trateaza, acest obiect este aruncat mai departe pana cand fie este tratat, fie programul se termina deoarece nu a existat nici un handler pentru eroare.
Aruncarea unei exceptii• Daca in cod apare o situatie
exceptionala si nu exista suficienta informatie pentru a fi tratata, informatia poate fi transmisa mai departe, intr-un context unde situatia poate fi rezolvata
• Transmiterea informatiei se realizeaza prin intermediul unui obiect care contine informatie relevanta despre situatia intalnita
• Obiectul este aruncat in afara contextului = aruncarea unei exceptii
MyException.h#ifndef MY_EXCEPTION_H#define MY_EXCEPTION_Hclass MyException{ const char* err_msg; public: MyException(const char* const m):err_msg(m)
{ }};#endif
Test.cpp#include "MyException.h"
void f(){ throw MyException("Mesaj");}int main(){ f(); return 0;}
Aruncarea unei exceptii• Throw:
– Se creeaza o copie a obiectului aruncat– Se returneaza aceasta copie din functia in care a fost intalnit,
chiar daca functia nu returna tipul de data al exceptiei in mod natural
– Executia continua intr-o parte speciala a codului – handlerul exceptiei
– Toate obiectele locale create in scopul in care a fost aruncata exceptia sunt distruse (“stack unwinding”)
– Se pot arunca oricate tipuri de exceptii este necesar– In mod obisnuit, pentru fiecare tip de anomalie se va arunca un
tip de exceptie diferit– Informatia este salvata in obiect, iar numele clasei exceptie
trebuie sa reflecte anomalia (Java: IOException, ClassNotFoundException, NullPointerException, IndexOutOfBoundsException, FileNotFoundException, etc)
Aruncarea unei exceptii
• Se poate arunca orice tip de data (inclusiv tipuri de date predefinite), dar de obicei se creeaza clase speciale
Prinderea unei exceptii
• Se realizeaza in interiorul unui handler de exceptie• Este nevoie de cate un handler de exceptie pentru fiecare tip de
exceptie care se doreste a fi prinsa• Daca in interiorul unei functii se arunca o exceptie sau se apeleaza
o functie care arunca o exceptie, corpul functiei este parasit din cauza exceptiei aruncate
• Daca se doreste ca aparitia lui throw in interiorul functiei sa duca la parasirea corpului functiei – bloc special in care se incearca rezolvarea problemei – blocul try
• Blocul try-catch – domeniu de vizibilitate normal
try{
//cod susceptibil (de exceptii)
}
Tratarea exceptiilor
• Handlerii de exceptii apar imediat dupa blocul try• Marcati prin cuvantul cheie catch
try{//cod susceptibil
….
}catch(Tip_1 id_1){//handler de exceptie Tip_1}
catch(Tip_2 id_2) {//handler de exceptie Tip_2}
…
catch(Tip_n id_n) {//handler de exceptie Tip_n}
Similar argumentelor unei functii
Exceptii
• 3 participanti la aruncarea/tratarea unei exceptii:
– Blocul try – marcheaza codul care ar putea sa genereze situatii de eroare
– Clauza catch – urmeaza imediat blocului try si contine codul care trateaza problema
– Instructiunea throw – modul in care codul cu probleme notifica codul apelant legat de aparitia unei probleme
Alocarea memoriei cu tratarea exceptiilor
#include <iostream>using namespace std;
int main(){ int* buf; try{ buf=new int[256]; if (buf==NULL) throw "Alocarea memoriei esuata!"; else delete [] buf; } catch (char* exc){ cerr<<exc<<endl; } return 0;}
Blocul TRY
Blocul CATCH
Instructiunea THROW
Constructori si destructori
• Controlul trece de la punctul in care apare THROW la un handler
• Obiectele create in scopul in care a fost aruncata exceptia sunt distruse AUTOMAT prin apelul destructorilor
• Daca constructorul unui element al unui vector arunca o exceptie, numai elementele construite ale vectorului vor fi distruse
Potrivirea exceptiilor
• La aruncarea unei exceptii, se cauta cel mai “apropiat” handler in raport cu ordinea in care acestia apar in cod
• La gasirea unei potriviri, cautarea se opreste
• Polimorfismul functioneaza
• E indicat sa prindem o exceptie prin referinta, pentru a evita apelul constructorului de copiere sau folosind pointeri
• Nu se fac conversii automate de tip in procesul de potrivire a exceptiilor
Conversii automate#include <iostream>
using namespace std;
class Exc1{
};
class Exc2{
public:
Exc2(Exc1){}
};
void f(){
throw Exc1();
}
int main(){
try{
f();
}catch(Exc2& e){cout<<"Exceptia 2"<<endl;}
catch(Exc1& e){cout<<"Exceptia 1"<<endl;}
return 0;
}
Constructor de conversie
Se executa deoarece NU se fac conversii automate de tip
Prinderea oricarui tip de exceptie
• Pentru a prinde orice tip de exceptie, se poate crea un handler care trateaza orice tip de exceptie folosind … pe postul listei de argumente
• catch(…){cout<<“orice exceptie “<<endl;}
• Este recomandat ca clauza catch(…) sa fie pusa ultima in lista handlerilor
Prinderea oricarui tip de exceptie
MyException.h
#ifndef MY_EXCEPTION_H#define MY_EXCEPTION_H
class MyException{ const char* err_msg; public: MyException(const char* const m):err_msg(m)
{} const char* const what(){return err_msg;}};
#endif
Test.cpp#include "MyException.h"#include <iostream>using namespace std;
void f(){ throw MyException("My Exception");}
int main(){try{ f();}catch(...) { cout<<"Nu se stie ce..."<<endl; } catch(MyException& e) {cout<<e.what()<<endl; } return 0;}
Se va intra pe aici
Rearuncarea unei exceptii
• Se doreste rearuncarea unei exceptii atunci cand exista niste resurse care trebuie eliberate (conexiuni in retea, memorie, etc)
• Se foloseste clauza throw fara nici un argument in interiorul unui handler
• De obicei, cand nu suntem interesati in cauza exceptiei, doar in a ne elibera resursele, folosim clauza catch(…) pentru a o prinde, a elibera resursele si apoi o aruncam mai departe
Rearuncarea unei exceptii
void g(){}
void f(){ char* s1; char* s2= new char[25]; try{ g(); }catch(...){delete [] s2; throw; } }
int main(){ f(); return 0;}
Rearuncarea unei exceptii#include <iostream>#include <fstream>using namespace std;void MyHandler(){ ifstream f("in.txt"); int m; try { f>>m; cout<<"m = "<<m<<endl; throw "hello"; f>>m; cout<<"m = "<<m<<endl; } catch (const char*) { f.close(); cout <<"Exceptie prinsa in MyHandler\n"; throw; //rethrow char* out of function }}int main(){ cout<< "Main start\n"; try { MyHandler(); } catch(const char*) { cout <<"Exceptie prinsa in Main\n"; } cout << "Main end"; return 0;}
Main startm=2Exceptie prinsa in MyHandlerExceptie prinsa in MainMain end
2 4
Exceptii neprinse
• Daca nici un handler nu trateaza o exceptie, se va apela functia terminate(), care apeleaza la randul sau abort() – iesirea din program
Specificarea exceptiilor
• Este posibila prezentarea multimii de exceptii pe care o functie le arunca direct sau indirect in cadrul declaratiei functiei– int getValue() throw (MyException*, char*, int);
• O functie fara nici o specificare a exceptiilor poate arunca orice exceptie– int f();
• O functie cu specificarea exceptiilor vida nu poate arunca nici o exceptie– int f () throw();
• Daca o functie arunca o exceptie nespecificata in lista exceptiilor va genera apelul functiei unexpected() →terminate()
Distrugerea obiectelor
• Sistemul de tratare a exceptiilor C++ garanteaza ca la parasirea domeniului de vizibilitate, toate obiectele create in acel domeniu de vizibilitate ai caror constructori s-au finalizat cu succes vor fi distruse prin apelarea automata a destructorilor
Distrugerea obiectelor#ifndef T_H#define T_H#include <iostream>using std::cout;
class Trace{ int objId; static int count;public: Trace(){objId=count++; cout<<"Object "<<objId<<"
created"<<endl; if(count==3) throw 3; } ~Trace() {cout<<"Destroying "<<objId<<endl;}};int Trace::count=0;#endif
#include "Trace.h"
int main(){try{Trace ob1;Trace array[5];Trace n2;}catch(int i){cout<<"Caught "<<i<<endl;}return 0;}
Object 0 createdObject 1 createdObject 2 created Destroying 1Destroying 0Caught 3
Nu se finalizeaza niciodata
Exceptii standard
• Derivate din clasa exception din <exception>
• 2 clase principale, definite in <stdexcept>, care include <exception>:– logic_error (transmiterea unui argument invalid, etc)– runtime_error (probleme hard, probleme cu memoria)
• Au cate un constructor cu argument de tip string (mesajul exceptiei)
• Metoda what() care returneaza mesajul de exceptie
Derivare din exceptii standard
#ifndef MY_EXC_H
#define MY_EXC_H
#include <stdexcept>
#include <iostream>
using namespace std;
class MyEx:public runtime_error{
public:
MyEx(const string& msg=""):runtime_error(msg){}
};
#endif
#include "MyException.h"
int main(){
try{
throw MyEx("mesaj ");
}catch(MyEx& e){cout<<e.what()<<endl;}
return 0;
}
Clase exceptie derivate
• Derivate din logic_error– domain_error– invalid_argument– length_error– out_of_range– bad_cast– bad_typeid
• Derivate din runtime_error– range_error– overflow_error– bad_alloc
Vector cu exceptii#ifndef ET_H#define ET_H#include <stdexcept>using namespace std;class ExceptionTrace:public runtime_error{
public: ExceptionTrace( char* m):runtime_error(m){}~ExceptionTrace(){}};#endif
#ifndef FVE_H#define FVE_H#include <string.h>#include "ExceptionTrace.h"
class FullVectorException:public ExceptionTrace{
public:FullVectorException(char*m):ExceptionTrace(m){}~FullVectorException(){}
};#endif
#ifndef IOBE_H#define IOBE_H#include "ExceptionTrace.h"
class IndexOutOfBoundsException:public ExceptionTrace{
public:
IndexOutOfBoundsException(char*m):ExceptionTrace(m){}~IndexOutOfBoundsException(){}
};
#endif
Vector.h#ifndef VECTOR_H#define VECTOR_H#include "FullVectorException.h"#include "IndexOutOfBoundsException.h"
class Vector{int* elem;int dim;int capac;
public:Vector(int=10);Vector(const Vector&);void operator +=(int) throw(FullVectorException);int operator [](int) throw(IndexOutOfBoundsException);void realoc();int vid() throw();
int dimensiune() throw(); ~Vector();};#endif
Vector.cpp#include "Vector.h"#include <iostream>using namespace std;
Vector::Vector(int d){elem= new int[d];dim=0;capac=d;
}
Vector::Vector(const Vector& v){ elem= new int[v.dim]; for (int i=0;i<v.dim;i++) elem[i]=v.elem[i]; dim=v.dim;}
void Vector::operator +=(int x) throw(FullVectorException){if(dim>=capac) throw FullVectorException("E plin vectorul");elem[dim++]=x;
}
Vector::~Vector(){ delete [] elem;}
int Vector::operator [](int i) throw(IndexOutOfBoundsException){if (i>=dim) throw IndexOutOfBoundsException("Indexul e prea mare");if (i<0) throw IndexOutOfBoundsException("Indexul e negativ");return elem[i];
}
void Vector::realoc(){int* aux = elem;elem= new int[dim+dim/2];for (int i=0;i<dim;i++)
elem[i]=aux[i];
capac=dim+dim/2;delete []aux;cout<<"realoc";
}
int Vector::vid() throw(){return dim==0;
}
int Vector::dimensiune() throw(){ return dim;}
Test.cpp#include "Vector.h"#include <iostream>using namespace std;
int main(){Vector v;try{
try{for (int i=0;i<15;i++)
v+=i;for(int i=2;;--i)
cout<<v[i]<<"\n";}catch(FullVectorException& e){
cout<<e.what()<<endl; v.realoc(); v+=11; throw;
}
catch(IndexOutOfBoundsException& e1){
cout<<e1.what()<<endl; throw;
}
catch(ExceptionTrace& e){
cout<<e.what()<<endl;
}
catch (...)
{cout<< "altceva";}
}catch(ExceptionTrace& e){
cout<<e.what()<<endl;
}
for(int i=0;i<v.dimensiune();i++)
cout<<v[i]<<" ";
return 0;
}
Spatii de nume• Defineste un domeniu de vizibilitate in care nu pot fi folositi identificatori duplicati
• Un spatiu de nume poate fi divizat la randul sau in mai multe spatii de nume
• Crearea unui spatiu de nume – similar unei clase
• Crearea de aliasuri de nume:– Namespace NumeLuuuuung{}– Namepace nume= NumeLuuuuung;
namespace MyLib{ //declaratii} Fara “;”
Spatii de nume
• Definitia unui spatiu de nume poate sa apara numai la nivel global, sau in interiorul altui domeniu de vizibilitate
• Definitia unui spatiu de nume se poate realiza in mai multe fisiere
#ifndef HEADER1_H#define HEADER1_H
namespace MyLib{ int x; void f(){}}#endif
#ifndef HEADER2_H#define HEADER2_H#include "Header1.h"
namespace MyLib{ int y; void g(){}}#endif
#include "Header1.h"#include "Header2.h"
int main(){MyLib::x=3;MyLib::y=5;MyLib::f();return 0;
}
Spatii de nume anonime
namespace{
int i,j;
}
• Referirea la identificatori se face fara a folosi operatorul ::
i=0;
j=5;
Utilizarea spatiilor de nume
1. Utilizarea operatorului de rezolutie
2. Utilizarea directivei using pentru a introduce toate numele
3. Utilizarea declaratiei using pentru a introduce cate un nume pe rand
Utilizarea operatorului ::
namespace X{
class Y{
static int i;
public:
void f();
};
class Z;
void func();
}
int X::Y::i=0;
class X::Z{
int u,v;
public:
Z(int);
…
}
X::Z::Z(int i){..}
void X:: func(){}
Directiva using• Permite importarea unui spatiu de nume
integral
#ifndef NSINT_H#define NSINT_H#include <iostream>using namespace std;
namespace Int{
class Integer{int val;
public:Integer(int =0);Integer(const Integer&);const Integer& operator+();const Integer operator-();const Integer operator+(const Integer&) const;const Integer operator-(const Integer&) const;Integer& operator=(const Integer&);bool operator==(const Integer&)const;bool operator!=(const Integer&)const;const Integer& operator++();const Integer operator++(int);operator double();operator int();Integer& operator+=(const Integer&);char* toString();friend ostream& operator<<(ostream& , Integer& );friend istream& operator>>(istream& , Integer& );
};
}#endif
Integer.cpp#include "NamespaceInt.h"using namespace Int;
Integer::Integer(int x):val(x){}
Integer::Integer(const Integer& x){val=x.val;
}
Integer::operator double(){ return double(val);}
Integer::operator int(){ return val;}const Integer& Integer::operator+(){
return *this;}
const Integer Integer::operator-(){ // cout<<"aa";
//if (val<0) return Integer(-val);
return Integer(-val);}
const Integer Integer::operator+(const Integer& a) const{return Integer(val+a.val);
}
…
Directiva using#ifndef NSM_H
#define NSM_H
#include "NamespaceInt.h"
namespace Math{ using namespace Int;
Integer a,b;
}#endif
#include "NamespaceMath.h"
using namespace Math;
int main(){
Integer a(6);
Integer c(8);
Integer sum=Math::a+c;
cout<<sum.toString()<<endl;
return 0;
}
Declaratia using
• Permite injectarea numelor dintr-un spatiu de nume unul cate unul
#ifndef UV_H#define UV_H#include <iostream>using namespace std;
namespace U{
inline void f(){cout<<"U::f()"<<endl;} inline void g(){cout<<"U::g()"<<endl;}}
namespace V{
inline void f(){cout<<"V::f()"<<endl;} inline void g(){cout<<"V::g()"<<endl;}}
#endif
#include "UV.h"
int main(){using namespace U;
f();
using V::f;f();g();U::f();return 0;}
U::f()V::f()U::g()U::f()
Declaratia using
#include <iostream>
int main(){
using std::cout;
using std::endl;
cout<<“Hello"<<endl;
return 0;
}
Spatii de nume imbricate (nested)
namespace A{ int i=5,j; inline f(){} namespace B{ int i=3; }}
#include <iostream>
using namespace std;#include "Namespace.h"
int main(){using namespace A;
cout<<A::i<<endl;cout<<A::B::i<<endl;return 0;}
53
Intrari/Iesiri (I/O)
• C: printf(…);scanf(…)
• Neajunsuri:– Lucreaza doar cu cele 4 tipuri de date predefinte (char, int, float,
double) si variatiile lor – nu este extensibila
• Posibila solutie:– Pentru fiecare tip de data nou introdus sa se supraincarce
functiile printf, scanf
• DAR– Stringul de formatare????
• Solutia:– Utilizarea STREAMURILOR
Stream-uri
• Definitie : un stream este un obiect care transporta si formateaza caractere de o lungime fixa (un flux de date de la o sursa (tastatura, fisier, zona de memorie) la o multime de destinatii (iesire: ecran, fisier, memorie)
• Caracteristica esentiala a procesarii streamurilor – datele sunt transmise sau primite de la un stream unul cate unul (serial)
• Tipuri de streamuri:– Streamuri de intrare (descendenti ai clasei istream)– Streamuri de iesire (descendenti ai clasei ostream)– Streamuri de intrare/iesire (descendenti ai clasei iostream)
Ierarhia de clase I/Oios
istream ostream
iostream
istream_withassign ostream_withassign
iostream_withassign
Declara tot ce este comun tuturor streamurilor
Defineste functii generice pentru iesire
Defineste functii generice pentru intrare
Iostream
• In biblioteca iostream – 2 operatori supraincarcati:– << (inserter) (folosit cu obiectul cout)– >>(extractor) (folosit cu obiectul cin)
• Pentru a salva timp la compilare in proiectele mari, e bine sa nu se includa <iostream>, ci <iosfwd>
#include <iosfwd>class Date{
friend std::ostream& operator<<(std::ostream&, const Date&);friend std::istream& operator>>(std::istream&, Date&);
};
Citirea de linii
• In mod obisnuit cin>> se opreste la primul blank
• Pentru a citi linii intregi – 3 posibilitati:
1. Functia membru get
2. Functia membru getline
• 3 argumente:
– Pointer la char – bufferul unde se va retine rezultatul
– Dimensiunea bufferului
– Caracterul de terminare (implicit ‘\n’)
• Diferente:
– get se opreste la primul caracter terminator, dar nu-l extrage
– getline extrage caracterul terminator, dar nu il pune in buffer
3. Functia globala getline <string>
– Citeste intr-un string
Get/getline membre
• Get
char* linie=new char[250];
cin.get(linie, 250);
cout<<linie<<endl;
while(strlen(linie)!=0){
cin.get();
cin.get(linie,250);
cout<<linie<<endl;
}
cin.get();
• Getline
char* linie=new char[250];
cin.getline(linie, 250);
cout<<linie<<endl;
while(strlen(linie)!=0){
cin.getline(linie,250);
cout<<linie<<endl;
}
Starea unui stream
• 4 flaguri folosite pentru a testa starea unui stream
• Valoarea unui flag poate fi testata apeland functiile:– good() – testeaza goodbit
– eof() –testeaza eofbit+failbit
– fail()- failbit sau badbit
– bad() - badbit
Flag Semnificatie
badbit Eroare fizica – eroare fatala, streamul nu mai poate fi folosit
eofbit A fost intalnit sfarsitul inputului
failbit Operatia de I/O a esuat (date invalide)
goodbit Nu sunt erori
Starea unui stream
• Pentru a schimba starea unui flag – clear()• Pentru a seta un flag: setstate(…)
myStream.setstate(ios::failbit)myStream.setstate(ios::badbit)
Starea unui stream#ifndef DATE_H#define DATE_H#include <iostream>#include <iomanip>using namespace std;
class Date{int day, month, year;
public:friend istream& operator>>(istream& is, Date& d);friend ostream& operator<<(ostream& os, const Date&);
};
istream& operator>>(istream& is, Date& d){is>>d.day;char slash='/';is>>slash;if (slash!='/')
is.setstate(ios::failbit);
is>>d.month;is>>slash;if(slash!='/')
is.setstate(ios::failbit);is>>d.year;return is;
}
ostream& operator<<(ostream& os, const Date& d){char fillc=os.fill('0');
os<<setw(2)<<d.day<<"/"<<setw(2)<<d.month<<"/"<<setw(4)<<setfill(fillc)<<d.year<<endl;return os;
}#endif
TEST.CPP#include "Date.h"#include <conio.h>using namespace std;int main(){Date d;cout<<"Introduceti data: ";cin>>d;if(cin.fail()) cout<<"Data in format
necorespunzator!"<<endl;else cout<<"Data introdusa este: "<<d;
return 0;}
Streamuri de tip fisier
• Pentru a deschide un fisier – se creeaza un obiect, iar constructorul deschide fisierul
• Fisierul nu trebuie inchis explicit – destructorul este apelat automat
• Pentru a crea un fisier – de intrare – ifstream– de iesire – ofstream– ambele - fstream
Moduri de deschidere a unui fisier• Se poate specifica modul de deschidere prin suprascrierea valorilor implicite
ale argumentelor constructorilor – folosim flaguri
• Fiecare obiect iostream contine un pointer la un obiect de tip streambuf – metoda rdbuf
Flag
ios::in Deschide un fisier de intrare
ios::out Deschide un fisier de iesire
ios::app Deschide un fisier de iesire pentru adaugare
ios::ate Deschide un fisier existent si se pozitioneaza la sfarsit
ios::trunc Trunchiaza fisierul daca exista deja
ios::bin Deschide un fisier in mod binar – implicit este text
Metoda rdbuf
#include <fstream>using namespace std;
int main(){ifstream f(“int.txt”);if(!f.fail())
cout<<f.rdbuf();return 0;
}
Tipareste pe ecran continutul fisierului
Pozitionarea in streamuri de I/O
• 2 modele:– Locatie absoluta – streampos– Locatie relativa – fseek – trece peste un numar de octeti de la
inceput, sfarsi, pozitia curenta
• Streampos– Prima data trebuie apelata functia “tell”
• tellp() - pentru ostream (put pointer)• tellg() – pentru istream (get pointer)
– Returneaza un pointer care poate fi folosit de catre functiile seekp() si seekg()
Pozitionarea in streamuri
• fseek – pozitionare relativa-foloseste versiuni supraincarcate ale lui seekp, seekg
• 2 argumente– Numarul de caractere peste care se face pozitionarea (poate fi
<0)– Directia de pozitionare:
• ios::beg (de la inceputul streamului)• ios::cur (de la pozitia curenta)• ios::end (de la sfarsitul streamului)
Pozitionarea in streamuri#include <fstream>#include <iostream>#include <conio.h>using namespace std;
int main(){ofstream out("a.txt");
out<<"Prima linie"<<endl;ofstream::pos_type p = out.tellp();out<<"A doua linie"<<endl;out.seekp(p);out.close();char* linie = new char[20];ifstream in("a.txt");
if(!in.fail()){//ma repozitionez unde am fost inaintein.seekg(p);//citesc si tiparesc
in.getline(linie, 20); cout<<linie<<endl;}else{cout<<"Eroare la deschidere";}
//de la pozitia curenta merg 5 caractere inapoiin.seekg(-5, ios::cur); in.getline(linie,20);cout<<linie<<endl;in.seekg(0, ios::beg); in.getline(linie,20);cout<<linie<<endl;
return 0;}
Formatarea streamurilor de iesire
• 2 modalitati:– Folosind functii membre– Manipulatori
• Flaguri de formatare– Clasa ios contine date membre care retin toate informatiile de
formatare• Variabile (precizia pentru date flotante, latimea campului de
iesire, caracterul cu care se completeaza iesirea)• Flaguri de formatare - restul
Flaguri de formatare
• 2 tipuri de flaguri:
– On/off
– Flaguri care lucreaza in grupuri
• Flaguri on/off
– Se seteaza cu setf(flag)/unsetf(flag)
Flag Efect
ios::skipws Sare peste caracterele albe
ios::showbase Pentru valorile intregi afiseaza baza
ios::showpoint Afiseaza punctul zecimal si zerouri de la coada pentru valori reale
ios::uppercase Afiseaza A-F pentru valori hexa
ios::showpos Afiseaza “+” pentru valorile pozitive
Ios:unitbuf Streamul este golit (flushed) dupa fiecare inserare
Campuri de formatare
• Flagurile de formatare lucreaza in grupuri, numai unul din flaguri poate fi setat la un moment dat
• Grupuri:– ios::basefield– ios::floatfield– ios::adjustfield
ios::basefield
ios::dec Formateaza valorile intregi in baza 10
ios::hex Formateaza valorile intregi in baza 16
ios::oct Formateaza valorile intregi in baza 8
Campuri de formatare
ios::floatfield
ios::scientific Format stiintific
ios::fixed Format fix
ios::adjustfield
ios::left Aliniere la stanga
ios::right Aliniere la dreapta
ios::internal Adauga caracterul de umplere (fill) intre semn si valoare
Dimensiune, umplere si precizie - functii
Functie Efect
int ios::width() Returneaza dimensiunea curenta
int ios::width(int n) Seteaza dimensiunea
int ios::fill Returneaza caracterul de umplere
int ios::fill(int n) Seteaza caracterul de umplere, returneaza anteriorul
int ios::precision() Returneaza precizia pt valori flotante (implicit 6)
int ios::precision(int n)
Seteaza precizia
Manipulatori
• Dubleaza actiunile realizate de functiile membre• Schimba starea streamului in loc de a procesa date
Manipulator Exemplu
showbase
noshowbase
showpos
noshowpos
uppercase
nouppercase
showpoint
noshowpoint
skipws
noskipws
left
right
internal
scientific
fixed
Manipulatori cu argumente
• <iomanip.h>
• setiosflags(formatFlags);
• resetiosflags(…)
• setbase(base)
• setfill(char)
• seprecision(int)
• setw(int)
cout<<setiosflags(ios::hex|ios::uppercase|ios::showpos);
cout<<a;
cout<<setbase(ios::hex)<<i<<endl;
cout<<setfill(‘ ‘)<<setw(20)<<5;
#include <fstream>#include <iostream>#include <iomanip>#include <conio.h>using namespace std;
int main(){ ofstream trc("trace.out"); int i = 47; float f = 2300114.414159; char* s = "Is there any more?"; trc << setiosflags(ios::unitbuf| ios::showbase |
ios::uppercase| ios::showpos); trc << i << endl; // Default to dec trc << hex << i << endl; trc << resetiosflags(ios::uppercase) << hex << i << endl; //aliniem la stanga trc.setf(ios::left, ios::adjustfield); trc << resetiosflags(ios::showbase)<< dec << setfill('0'); trc << "fill char: " << trc.fill() << endl; trc << setw(10) << i << endl;
//aliniem la dreapta // trc.setf(ios::right, ios::adjustfield); trc<<"ACUM ALNIEM LA DREAPTA"<<endl; trc <<right<<setw(10) << i << endl; //aliniem internal trc<<"ACUM ALNIEM INTERNAL"<<endl; // trc.setf(ios::internal, ios::adjustfield);//sau trc <<internal<< setw(10) << i << endl; trc << i << endl; // Without setw(10)
Trace.out
+470X2F0x2f
fill char: 0+470000000
ACUM ALINIEM LA DREAPTA0000000+47
ACUM ALINIEM INTERNAL
+000000047+47
trc << resetiosflags(ios::showpos)<< setiosflags(ios::showpoint)<< "prec = " << trc.precision() << endl;
trc.setf(ios::scientific, ios::floatfield); trc<< setiosflags(ios::uppercase)<<f<<endl; trc <<resetiosflags(ios::uppercase)<<f<<endl;
trc.setf(ios::fixed, ios::floatfield); trc<<f<<endl;
trc << setprecision(20); trc << "prec = " << trc.precision() << endl; trc << f << endl;
trc.setf(ios::scientific, ios::floatfield); trc << f << endl;
trc << setw(10) << s << endl; trc<<setfill(' ')<<setw(40) << s << endl; //trc << setw(40) << s << endl;
// trc.setf(ios::left, ios::adjustfield); trc << left<<setw(40) << s << endl; return 0;}
prec = 6
2.300115E+0062.300115e+006
2300114.500000
prec = 202300114.50000000000000000000
2.30011450000000000000e+006
Is there any more? Is there any more?
Is there any more?