Biblioteca
Tutora
BibliotecaInformatică și TIC › clasa a XI-a

Fișiere

Lucrul cu fișiere text și binare în limbajul C/C++.

Bacalaureat

De ce fișiere: date persistente, acces prin flux

Variabilele unui program trăiesc în memoria internă (RAM) și dispar la terminarea execuției. Un fișier este o colecție de date memorată pe un suport extern (disc), care persistă între rulări — de aceea toate problemele de BAC care spun „datele se citesc din fișierul bac.txt” presupun lucrul cu fișiere.

În C++, legătura dintre program și fișier se face printr-un flux (stream):

Declararea și deschiderea tipică: `ifstream f(„bac.txt”);` — obiectul f se folosește apoi exact ca cin: `f >> x;`. Analog, `ofstream g(„out.txt”);` se folosește ca cout: `g << rezultat;`.

Două subtilități care se punctează:

După terminarea prelucrării, fișierul se închide cu `f.close()` — la fișierele de ieșire, închiderea garantează că datele din zonele tampon ajung efectiv pe disc.

Citirea din fișiere text: operatorul >> și citirea până la sfârșit

Un fișier text conține caractere organizate în linii, separate prin marcaje de sfârșit de linie; numerele sunt memorate ca șiruri de cifre, lizibile pentru om.

Citirea cu `f >> x` funcționează ca la tastatură: sare peste spații albe (spații, taburi, sfârșituri de linie) și citește următoarea valoare de tipul lui x. Consecință importantă: pentru numere, nu contează dacă valorile sunt câte una pe linie sau toate pe o linie — operatorul >> le citește la fel. Această echivalență e exploatată des în enunțuri.

Șablonul fundamental, cerut la aproape orice problemă: citirea până la sfârșitul fișierului când numărul valorilor nu e cunoscut:

Expresia `f >> x` are ca valoare fluxul însuși, care se convertește la fals când citirea a eșuat — deci bucla se oprește exact după ultima valoare citită cu succes.

Pentru text cu spații apar instrumente suplimentare:

Capcana clasică: amestecul lui >> cu getline. După `f >> n`, marcajul de sfârșit de linie rămâne neconsumat în flux, iar un getline imediat următor citește linia vidă rămasă, nu linia dorită — se rezolvă consumând explicit restul liniei (de exemplu cu `f.get()` sau `f.ignore()`).

Scrierea în fișiere text și prelucrări tipice de examen

Scrierea se face cu `g << valoare`, ca la cout. Detaliul care pierde puncte la corectare: separatorii trebuie scriși explicit. `g << a << b;` lipește numerele (12 și 3 devin 123); corect este `g << a << ' ' << b;` sau cu `'\n'` între valori, exact cum cere enunțul (valori separate prin spațiu / câte una pe linie).

Problemele de BAC cu fișiere urmează câteva șabloane pe care merită să le stăpânești ca atare:

Distincția „se poate pe flux / trebuie vector” e chiar substanța multor subiecte: enunțurile precizează că fișierul poate avea până la un milion de valori tocmai ca să sancționeze memorarea inutilă în vector acolo unde o singură trecere ajunge.

Pentru modificarea unui fișier text nu există inserare pe loc: se citește fișierul sursă, se scrie versiunea transformată într-un fișier nou, iar la final, dacă se cere, fișierul nou îl înlocuiește pe cel vechi. Fișierul text este în esență secvențial: ca să ajungi la a suta valoare, treci prin primele 99.

Fișiere binare și accesul direct

Un fișier binar memorează datele exact în reprezentarea lor internă din memorie: un int de 4 octeți ocupă fix 4 octeți în fișier, indiferent de valoare. Comparația cu fișierul text e întrebare de teorie standard:

Operațiile în C++ se fac cu `read` și `write` pe fluxuri deschise cu modul `ios::binary`, transferând blocuri de octeți dintr-o structură în fișier și invers.

Dimensiunea fixă a înregistrărilor deblochează accesul direct (aleator): poziția înregistrării k se calculează aritmetic, `k * dimensiunea_înregistrării`, iar indicatorul de poziție al fișierului poate fi mutat acolo fără parcurgerea înregistrărilor anterioare:

Astfel, într-un fișier binar se poate modifica o înregistrare pe loc — exact ce nu se poate în fișierul text. De aici aplicația tipică: evidențe de tip bază de date simplă (elevi, produse), unde înregistrarea k se citește, se modifică și se rescrie la aceeași poziție. Confuzia frecventă: accesul direct ține de structura binară cu înregistrări de lungime fixă, nu e o proprietate magică a oricărui fișier.

Închidere, stări de eroare și disciplina lucrului cu fișiere

Fluxurile de fișiere au stări care trebuie verificate, pentru că operațiile cu discul pot eșua fără ca programul să se oprească singur:

De aici cea mai cunoscută greșeală de logică: bucla `while (!f.eof()) { f >> x; prelucrează x; }` prelucrează ultima valoare de două ori (sau o valoare reziduală): când ultima citire reușită consumă tot fișierul, eof încă nu e setat, bucla mai intră o dată, citirea eșuează, x rămâne cu valoarea veche și e prelucrat din nou. Forma corectă rămâne `while (f >> x)`, care testează rezultatul citirii, nu starea anterioară a fluxului.

Închiderea cu `close()` are două roluri: eliberează resursa sistemului de operare și, la fișierele de ieșire, golește buffer-ul — scrierile sunt ținute temporar în memorie și abia la close (sau flush) ajung garantat pe disc. Un program întrerupt înainte de close poate lăsa fișierul de ieșire incomplet.

Disciplina completă, în ordinea care se cere și la examen: deschidere → verificarea deschiderii → prelucrare → închidere. Același flux poate fi refolosit pentru alt fișier doar după închiderea celui curent.

De reținut

fișier
colecție de date memorată pe un suport extern de stocare, care persistă după terminarea execuției programului, spre deosebire de variabilele din memoria internă
ifstream / ofstream
clasele C++ pentru fluxuri de fișiere: ifstream pentru citire (se folosește ca cin), ofstream pentru scriere (se folosește ca cout)
fișier text
fișier care memorează datele ca șiruri de caractere organizate în linii, lizibil pentru om; numerele sunt stocate ca șiruri de cifre și necesită conversie la citire
fișier binar
fișier care memorează datele exact în reprezentarea lor internă din memorie; compact, rapid, cu înregistrări de dimensiune fixă care permit acces direct
citire până la sfârșitul fișierului
șablonul while (f >> x), care se oprește exact după ultima citire reușită, pentru că expresia de citire se evaluează la fals când citirea eșuează
acces secvențial
mod de acces în care datele se parcurg în ordine, de la început; pentru a ajunge la a k-a valoare trebuie citite toate cele dinaintea ei — modul natural al fișierelor text
acces direct
mod de acces în care poziția unei înregistrări se calculează aritmetic și indicatorul de poziție se mută direct acolo (seekg/seekp), posibil în fișiere binare cu înregistrări de lungime fixă
ios::app
mod de deschidere a unui fișier de ieșire prin care scrierile se adaugă la sfârșitul conținutului existent, în loc ca fișierul să fie suprascris
close()
operația de închidere a fișierului, care eliberează resursa și golește buffer-ul de scriere, garantând că datele ajung efectiv pe disc

Greșeli frecvente

Greșit: Bucla while (!f.eof()) urmată de citire și prelucrare ar citi corect tot fișierul
Corect: Șablonul cu eof prelucrează ultima valoare de două ori, pentru că eof se setează abia după o citire eșuată; forma corectă este while (f >> x), care testează direct reușita citirii
Greșit: Deschiderea pentru scriere a unui fișier existent ar păstra conținutul vechi și ar scrie în continuare
Corect: Deschiderea implicită cu ofstream șterge conținutul existent (trunchiere); pentru adăugare la sfârșit trebuie specificat explicit modul ios::app
Greșit: g << a << b; ar scrie cele două numere separate în fișier
Corect: Operatorul << nu adaugă niciun separator: 12 și 3 devin 123 în fișier; spațiul sau sfârșitul de linie trebuie scrise explicit între valori
Greșit: Orice problemă cu fișiere s-ar rezolva citind mai întâi toate datele într-un vector
Corect: Statisticile pe flux (minim, sumă, comparare cu valoarea precedentă) se rezolvă cu o singură trecere, fără memorare; la un milion de valori, memorarea inutilă poate depăși memoria și e penalizată de cerință
Greșit: Într-un fișier text s-ar putea modifica o valoare pe loc, ca într-un vector
Corect: Fișierul text este secvențial: modificarea presupune rescrierea într-un fișier nou; modificarea pe loc a unei înregistrări este posibilă doar în fișiere binare cu înregistrări de lungime fixă, prin seekg/seekp

Test — 6 întrebări ca la examen

1. Un program C++ trebuie să citească numere dintr-un fișier text. Clasa de flux potrivită este:
  1. ofstream
  2. ifstream
  3. iostream
  4. fstream deschis doar pentru scriere
Vezi răspunsul
ifstream. ifstream este fluxul de intrare din fișier (input file stream) și se folosește exact ca cin. ofstream — distractorul simetric — este pentru scriere; confuzia i/o din prefixe este cea mai banală și cea mai frecventă eroare la acest capitol.
2. Fișierul text date.txt conține un număr necunoscut de valori întregi, separate prin spații și sfârșituri de linie. Citirea corectă a tuturor valorilor se face cu:
  1. while (!f.eof()) { f >> x; s = s + x; }
  2. for (i = 0; i < 100; i++) f >> x;
  3. while (f >> x) s = s + x;
  4. getline(f, x) apelat o singură dată
Vezi răspunsul
while (f >> x) s = s + x;. while (f >> x) se oprește exact după ultima citire reușită, indiferent cum sunt distribuite valorile pe linii. Varianta cu !f.eof() e distractorul cel mai tentant: pare echivalentă, dar adună ultima valoare de două ori, pentru că eof se activează abia după o citire eșuată.
3. Un fișier de ieșire rezultate.txt există deja și conține date. Programul îl deschide cu ofstream g(„rezultate.txt”); și scrie o valoare. Ce se întâmplă cu vechiul conținut?
  1. rămâne intact, valoarea nouă se adaugă la sfârșit
  2. este șters, fișierul conține doar valoarea nou scrisă
  3. programul se oprește cu eroare, fișierul existând deja
  4. vechiul conținut se mută automat într-un fișier de rezervă
Vezi răspunsul
este șters, fișierul conține doar valoarea nou scrisă. Deschiderea implicită pentru scriere trunchiază fișierul: conținutul vechi dispare. Adăugarea la sfârșit — prima variantă, capcana obișnuită — se obține doar cerută explicit, cu modul ios::app; nicio salvare de rezervă nu se face automat.
4. Care dintre următoarele prelucrări ale unui fișier text cu un milion de numere NU necesită memorarea valorilor într-un vector?
  1. afișarea valorilor în ordine inversă citirii
  2. sortarea crescătoare a valorilor
  3. determinarea celei mai lungi secvențe de valori consecutive egale
  4. afișarea medianei valorilor
Vezi răspunsul
determinarea celei mai lungi secvențe de valori consecutive egale. Secvența de valori egale se detectează comparând fiecare valoare citită cu precedenta — ajung două variabile și un contor, într-o singură trecere. Inversarea, sortarea și mediana au nevoie de toate valorile simultan, deci de vector; inversarea e distractorul tentant pentru că pare o simplă „afișare”.
5. Accesul direct la a k-a înregistrare, fără parcurgerea celor dinaintea ei, este posibil:
  1. în orice fișier text, folosind getline de k ori
  2. în fișiere binare cu înregistrări de lungime fixă, folosind seekg
  3. doar în fișierele deschise simultan pentru citire și scriere
  4. în fișiere text, dacă valorile sunt sortate crescător
Vezi răspunsul
în fișiere binare cu înregistrări de lungime fixă, folosind seekg. Poziția înregistrării k se calculează k înmulțit cu dimensiunea înregistrării doar când toate înregistrările au aceeași lungime — situația fișierului binar; seekg sare direct acolo. getline de k ori este chiar parcurgere secvențială, iar sortarea valorilor nu schimbă cu nimic natura secvențială a fișierului text.
6. Un program scrie rezultate într-un fișier, dar este întrerupt brusc înainte de apelul close(). Care este riscul principal?
  1. fișierul devine binar în loc de text
  2. datele din buffer nepredate discului se pierd, fișierul rămâne incomplet
  3. fișierul se șterge automat de pe disc
  4. niciun risc, operatorul << scrie direct pe disc
Vezi răspunsul
datele din buffer nepredate discului se pierd, fișierul rămâne incomplet. Scrierile trec printr-un buffer în memorie și ajung pe disc la golirea acestuia — garantat la close(); întreruperea înainte poate lăsa pe disc doar o parte din date. Ultima variantă este distractorul care pică cei mai mulți: << scrie în buffer, nu direct pe disc, tocmai de aceea închiderea contează.
Deschide varianta interactivă — cu AI care îți explică
← Algoritmi de sortare și căutareProgramare orientată pe obiecte (POO) →
BiologieChimieEconomieFilosofieFizicăGeografieInformatică și TICIstorieLogică și argumentareMatematicăPsihologieLimba și literatura română