Sunteți pe pagina 1din 5

TEMA 2

Tipul de date fișier. Funcții de prelucrare a fișierelor.

Fişierul este o colecţie de informaţii ordonată în înregistrări. Fişierele sunt structuri de date
organizate pe suporturi externe.

Clasificarea fişierelor se poate face după diferite criterii, cum ar fi:


1. d.p.d.v. al conținutului:
 fişiere text – memorează caractere organizate pe linii. O linie constituie înregistrare şi
poate avea dimensiune variabilă. Sfârşitul unei linii, eol (end of line), este marcată prin
caracterele <CR><LF> (0D 0A) (revenire la început de rând şi avans la rândul
următor). De exemplu - fişierele sursă sunt fişiere text (exemplu.cpp);
 fişiere cu tip – fişiere care au înregistrări de un anumit tip (elementar sau structurat);
 fişiere fără tip – fişiere binare.
2. d.p.d.v. al accesului:
 cu acces secvențial – informația poate fi prelucrată doar în ordinea în care a fost
înregistrată în fişier;
 cu acces direct – componentele pot fi prelucrate în orice ordine (chiar şi secvențial).
Înainte de orice prelucrare, trebuie specificată poziția ocupată de componentă în fişier.
3. d.p.d.v. al operațiilor de scriere/citire în/din fişier:
 de intrare – e permisă doar operația de citire – informația e preluată în memorie – de
exemplu, fişierul standard Input – asociat cu tastatura;
 de ieşire – e permisă doar operația de scriere (stocarea informației suport magnetic) – de
exemplu, fişierul standard Output – asociat cu ecranul;
 de intrare/ieşire – fişierele pe suport magnetic pot fi exploatate atât ca fişiere de intrare,
cât şi ca fişiere de ieşire, având astfel posibilitatea de a reactualiza informația.

Principalele funcţii sunt grupate în tabelul de mai jos:

Verificarea steagului de stare

Următoarele funcții membre există pentru a verifica stările specifice ale unui flux (toate returnând o
valoare bool):
- bad() - Returnează adevărat dacă o operație de citire sau scriere nu reușește. De exemplu, în
cazul în care încercăm să scriem într-un fișier care nu este deschis pentru scriere sau dacă
dispozitivul în care încercăm să scrie nu mai rămâne spațiu.
- fail () - Se întoarce adevărat în aceleași cazuri ca și bad (), dar și în cazul în care se întâmplă
o eroare de format, ca atunci când este extras un caracter alfabetic atunci când încercăm să
citim un număr întreg.
- eof () - Se întoarce adevărat dacă un fișier deschis pentru citire a ajuns la sfârșit.
- good() - Este cel mai generic steag de stat: returnează fals în aceleași cazuri în care apelarea
oricăreia dintre funcțiile anterioare ar reveni adevărat. Rețineți că binele și răul nu sunt opuse
exacte (bune verifică mai multe steaguri de stat simultan).
- clear () - Funcția de membru poate fi folosită pentru a reseta steagurile de stare.

Poziționarea fluxului

Toate fluxurile de obiecte de intrare / ieșire mențin intern cel puțin o poziție internă:
- ifstream, ca istream, păstrează o poziție de obținere internă cu locația elementului care trebuie
citit în următoarea operație de intrare.
- ofstream, ca ostream, păstrează o poziție internă de poziție cu locația unde urmează să fie
scris următorul element.

În cele din urmă, fstream, păstrează atât poziția get, cât și poziția put, precum iostream. Aceste poziții
ale fluxului intern indică locațiile din fluxul în care se efectuează următoarea operație de citire sau
scriere. Aceste poziții pot fi observate și modificate folosind următoarele funcții ale membrilor:

 tellg () și tellp ()
Aceste două funcții ale membrilor fără parametri returnează o valoare a fluxului de tip membru, care
este un tip reprezentând poziția de obținere curentă (în cazul telegului) sau poziția put (în cazul teled).

 seekg() și seekp()
Aceste funcții permit schimbarea locației pozițiilor get and put. Ambele funcții sunt supraîncărcate cu
două prototipuri diferite.
Prima formă este:
- seekg (poziția);
- seekp (poziție);
Folosind acest prototip, indicatorul de flux este schimbat în poziția absolută (contând de la începutul
fișierului). Tipul acestui parametru este streampos, care este același tip cu cel returnat de funcțiile
tellg și tellp.
Cealaltă formă pentru aceste funcții este:
- căutare (compensare, direcție);
- căutare (compensare, direcție);
Folosind acest prototip, poziția get sau put este setată la o valoare de compensare în raport cu un
anumit punct determinat de direcția parametrului. compensarea este de tip streamoff. Și direcția este
de tip căutător, care este un tip enumerat care determină punctul de unde este contorizat compensarea
și care poate lua oricare dintre următoarele valori:

ios::beg compensare numărată de la începutul fluxului


ios::cur compensare contorizată din poziția actuală
ios::end compensare numărată de la sfârșitul fluxului
Următorul exemplu folosește funcțiile de membru pe care tocmai le-am văzut pentru a obține
dimensiunea unui fișier:

#include <iostream>
#include <fstream>
using namespace std;
int main () {
streampos begin,end;
ifstream fisier("exemplu.bin", ios::binary);
begin = fisier.tellg();
fisier.seekg (0, ios::end);
end = fisier.tellg();
fisier.close();
cout << "Dimensiunea este: " << (end-begin) << " byte.\n";
return 0;
}

În fișierul exemplu.bin trebuie să scrieți următoarele date binare: 1001 1010 1011 1100 1101

Rezultat

Observați tipul pe care l-am folosit pentru început și sfârșit pentru variabile: streampos size. Unde
streampos este un tip specific utilizat pentru poziționarea tampon și fișier și este tipul returnat de
file.tellg (). Valorile de acest tip pot fi scăzute în siguranță din alte valori de același tip și pot fi, de
asemenea, convertite într-un tip întreg suficient de mare pentru a conține dimensiunea fișierului.

Aceste funcții de poziționare a fluxului folosesc două tipuri particulare: streampos și streamoff. Aceste
tipuri sunt de asemenea definite ca tipuri de membri ale clasei de flux:

Tipul Tipul de membru Descrierea


Definit ca fpos <mbstate_t>.
streampos ios::pos_type Poate fi convertită în / din flux și poate fi adăugată sau scăzută valori de
aceste tipuri.
Este un alias al unuia dintre tipurile fundamentale integrale (cum ar fi
streamoff ios::off_type
int sau long long).

Notă:
 Fiecare dintre tipurile de membri de mai sus este un alias al echivalentului său non-membru
(sunt exact același tip). Nu contează care este folosit.
 Tipurile de membri sunt mai generice, deoarece sunt aceleași pe toate obiectele de flux (chiar
și pe fluxurile care folosesc tipuri exotice de caractere), dar tipurile non-membre sunt utilizate
pe scară largă în codul existent din motive istorice.

Fișiere binare

Pentru fișierele binare, citirea și scrierea datelor cu operatorii de extragere și inserare (<< și >>) și
funcții precum getline nu este eficientă, deoarece nu este necesar să formatăm date și este posibil ca
datele să nu fie formatate în linii. Fluxurile de fișiere includ două funcții membre special concepute
pentru citirea și scrierea datelor binare secvențial: write și read.
Primul (scrie) este o funcție de membru a ostreamului (moștenit de ofstream). Și cititul este o funcție
de membru a istream (moștenit de ifstream). Obiectele clasei fstream au ambele. Prototipurile lor
sunt:
 write (memory_block, size);
 read (memorie_blocare, dimensiune);

În cazul în care memory_block este de tip char * (pointer to char) și reprezintă adresa unui tablou de
octeți în care sunt stocate elementele de date citite sau de unde sunt luate elementele de date care
urmează să fie scrise. Parametrul de dimensiune este o valoare întreagă care specifică numărul de
caractere care trebuie citite sau scrise din / către blocul de memorie.

#include <iostream>
#include <fstream>
using namespace std;
int main () {
streampos size;
char * memblock;
ifstream file ("exemplu.bin", ios::in|ios::binary|ios::ate);
if (file.is_open()){
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "Intregul continut al fisierului este in memorie.\n";
delete[] memblock;
}
else cout << "Fisierul nu poate fi deschis.\n";
return 0;
}

În fișierul exemplu.bin trebuie să scrieți următoarele date binare: 1001 1010 1011 1100 1101

Rezultat

În acest exemplu, întregul fișier este citit și stocat într-un bloc de memorie. Să examinăm cum se face
acest lucru:

În primul rând, fișierul este deschis cu indicatorul ios :: ate, ceea ce înseamnă că indicatorul
get va fi poziționat la sfârșitul fișierului. În acest fel, atunci când apelăm la tellg (), vom obține direct
dimensiunea fișierului.
După ce am obținut dimensiunea fișierului, solicităm alocarea unui bloc de memorie suficient
de mare pentru a reține întregul fișier: memblock = new char[size].
Chiar după aceea, procedăm la setarea poziției de obținere la începutul fișierului (amintiți-vă
că am deschis fișierul cu acest pointer la sfârșit), apoi citim întregul fișier și în final îl închidem:
- file.seekg (0, ios :: beg);
- file.read (memblock, dimensiune);
- file.close ();

În acest moment am putea opera cu datele obținute din fișier. Dar programul nostru anunță pur și
simplu că conținutul fișierului este în memorie și apoi se termină.
Buffere și sincronizare

Când funcționăm cu fluxuri de fișiere, acestea sunt asociate unui obiect tampon intern de tip
streambuf. Acest obiect tampon poate reprezenta un bloc de memorie care acționează ca un
intermediar între flux și fișierul fizic. De exemplu, cu un flux în flux, de fiecare dată când este apelată
funcția de membru (care scrie un singur caracter), caracterul poate fi inserat în acest tampon
intermediar în loc să fie scris direct în fișierul fizic cu care este asociat fluxul.
Sistemul de operare poate defini, de asemenea, alte niveluri de memorie tampon pentru citire și
scriere în fișiere.
Când bufferul este curățat, toate datele conținute în acesta sunt scrise pe suportul fizic (dacă este
un flux de ieșire). Acest proces se numește sincronizare și are loc în oricare dintre următoarele
circumstanțe:
- Când fișierul este închis: înainte de închiderea unui fișier, toate bufferele care nu au fost încă
spălate sunt sincronizate și toate datele în așteptare sunt scrise sau citite pe suportul fizic.
- Când tamponul este plin: tampoanele au o anumită dimensiune. Când bufferul este complet,
acesta este sincronizat automat.
- În mod explicit, cu manipulatorii: Când anumiți manipulatori sunt folosiți în fluxuri, are loc o
sincronizare explicită. Acești manipulatori sunt: flush și endl.
- În mod explicit, cu funcția de membru sincronizare (): Apelarea funcției de membru
sincronizare () provoacă o sincronizare imediată. Această funcție returnează o valoare int
egală cu -1 dacă fluxul nu are un tampon asociat sau în caz de eșec. În caz contrar (dacă
bufferul de flux a fost sincronizat cu succes), acesta returnează 0.

Probleme propuse:

1. numarul de valori pare/impare din sir


2. de cate ori apare in sir o valoare data Y?
3. care este valoarea maxima/minima din sir?
4. cate valori din sir au o proprietate anume (numar prim, palindrom, …)
5. numarul de schimbari de semn din sir
6. numarul de schimbari de paritate (par-impar si impar=par)
7. numarul de “vai” si “dealuri” (o vale este o succesiune de tipul 7-3-5; un deal este o
sucesiune de tipul 3-7-5)
8. lungimea maxima a unui subsir crescator
9. lungimea maxima a unui subsir de valori cu aceeasi paritate

S-ar putea să vă placă și