Fișiere
Elevii învață să lucreze cu fișiere text pentru stocarea și prelucrarea datelor persistente.
De ce avem nevoie de fișiere
Până acum, programele tale primeau datele de la tastatură și afișau rezultatele pe ecran. Problema: când programul se închide, totul dispare — variabilele trăiesc doar în memoria RAM, care se golește la oprirea programului. Ca datele să supraviețuiască, ele trebuie salvate pe disc, într-un fișier.
Un fișier este o colecție de date memorată pe un suport de stocare (SSD, hard disk, stick USB), identificată printr-un nume și o extensie (de exemplu note.txt). Spre deosebire de RAM, discul păstrează datele și după oprirea calculatorului — spunem că fișierele oferă persistența datelor.
În programare, la clasa a VII-a lucrăm cu fișiere text: fișiere care conțin caractere lizibile, organizate pe rânduri — exact ce ai vedea deschizându-le cu Notepad. Numerele sunt scrise ca șiruri de cifre despărțite prin spații sau rânduri noi. Prin contrast, fișierele binare (imagini, muzică, programe executabile) conțin octeți care nu sunt text și arată ca niște semne fără sens într-un editor — ele se studiază la liceu.
De ce preferă problemele fișierele în locul tastaturii?
- datele multe (sute de numere) nu pot fi tastate fără greșeli la fiecare rulare;
- testarea devine repetabilă: același fișier de intrare → același rezultat;
- exact așa funcționează concursurile de informatică: programul primește date din fișier de intrare și scrie rezultatele în fișier de ieșire, iar evaluarea e automată.
Deschiderea și închiderea fișierelor în C++
Ca să lucrezi cu fișiere în C++, incluzi biblioteca <fstream> și folosești două tipuri de obiecte-flux, surori cu cin și cout:
- ifstream (input file stream) — flux de citire dintr-un fișier;
- ofstream (output file stream) — flux de scriere într-un fișier.
Declararea și deschiderea se fac de obicei împreună:
ifstream fin(numele fișierului de intrare); ofstream fout(numele fișierului de ieșire);
Din acest moment, fin se folosește exact ca cin, iar fout exact ca cout — aceleași săgeți >> și <<. Aceasta e marea eleganță a limbajului: schimbi doar sursa datelor, restul programului rămâne identic.
Reguli și capcane la deschidere:
- fișierul de intrare trebuie să existe deja și să fie în același folder cu programul (dacă dai doar numele, fără cale). Cel mai frecvent motiv pentru care „programul nu citește nimic” este fișierul inexistent sau pus în alt folder;
- fișierul de ieșire nu trebuie să existe: ofstream îl creează automat; dacă există deja, conținutul vechi se șterge la deschidere — atenție, se pierde fără avertisment;
- la final, fișierele se închid: fin.close(); fout.close(); Închiderea garantează că tot ce ai scris ajunge efectiv pe disc (datele trec printr-o zonă tampon — buffer — și abia închiderea le „împinge” sigur în fișier). Uitarea lui close() la fișierul de ieșire poate lăsa fișierul gol sau incomplet.
Citirea datelor din fișier
Citirea cu fin >> variabila funcționează ca la tastatură: sare peste spații și rânduri noi și extrage următoarea valoare. Pentru un fișier care conține pe primul rând numărul n și pe al doilea rând n numere, citirea este:
fin >> n; for (i = 0; i < n; i++) fin >> v[i];
Observă că programului nu îi pasă dacă numerele sunt pe același rând sau pe rânduri diferite — operatorul >> le găsește oriunde. Aceasta e o sursă de mirare la început: aranjarea pe rânduri contează pentru ochiul omului, nu pentru >>.
Situația specială, cerută des în probleme: fișierul conține numere fără să știm câte — citim până se termină fișierul. Idiomul consacrat:
while (fin >> x) { prelucrează x }
Expresia fin >> x este adevărată cât timp citirea reușește și devine falsă la sfârșitul fișierului (end of file — EOF). Bucla se oprește singură exact când datele s-au terminat — șablonul standard pentru „se citesc toate numerele din fișier”.
Două greșeli de evitat:
- recitirea: după ce ai parcurs fișierul până la capăt, nu mai poți citi din nou de la început fără să îl închizi și să îl redeschizi — fluxul a rămas la sfârșit;
- citirea cu >> după EOF nu umple variabila cu date noi; dacă nu verifici reușita citirii, prelucrezi valori rămase de la pasul anterior — de aceea condiția de citire stă chiar în while.
Scrierea datelor în fișier
Scrierea cu fout << valoare este oglinda perfectă a lui cout: aceleași reguli, aceleași obiceiuri:
- valorile nu se despart automat: fout << a << b; le scrie lipite. Separatorii — spațiu sau rând nou — se scriu explicit: fout << a << ' ' << b << endl;
- poți scrie și mesaje text, și valori, în orice combinație;
- afișarea unui vector în fișier: for (i = 0; i < n; i++) fout << v[i] << ' ';
Ce trebuie să îți intre în reflex la probleme:
- formatul de ieșire cerut de enunț este lege: dacă se cere „numerele pe un singur rând, despărțite prin câte un spațiu”, exact asta trebuie să produci — evaluarea automată compară fișierul tău caracter cu caracter cu cel oficial. Un spațiu lipsă sau un rând nou în plus înseamnă răspuns respins, chiar dacă valorile sunt corecte;
- rândul nou se scrie cu endl sau '\n' — ambele acceptate;
- un program poate folosi simultan fișier de intrare și de ieșire: citește cu fin, calculează, scrie cu fout. Tiparul complet al unei probleme: deschide ambele fișiere → citește → prelucrează → scrie → închide ambele fișiere.
Mai ține minte diferența de comportament: dacă rulezi programul de două ori, fișierul de ieșire este rescris de la zero de fiecare dată (conținutul vechi dispare la deschidere), nu se adaugă la coadă. Modul de scriere „cu adăugare” (append) există, dar nu este comportamentul implicit și nu se cere la acest nivel.
Aplicații tipice cu fișiere text
Problemele cu fișiere sunt aceleași probleme pe care le știi deja — sume, maxime, numărări, vectori — doar că datele vin din fișier și rezultatele pleacă în fișier. Tiparele consacrate:
- Prelucrare la citire, fără memorare: pentru suma, media, maximul sau numărarea valorilor din fișier NU e nevoie de vector — citești cu while (fin >> x) și actualizezi acumulatorul din mers. Vectorul devine necesar doar când datele trebuie revizitate (afișare în ordine inversă, comparații între elemente aflate departe unul de altul);
- Copierea cu transformare: citești fiecare număr, scrii în fișierul de ieșire varianta transformată (dublul lui, doar cele pare etc.);
- Numărul de valori din fișier: k = 0; while (fin >> x) k++;
- Maximul și a doua cea mai mare valoare, ambele actualizate la fiecare citire — exemplu clasic de prelucrare fără vector;
- Fișier cu n cunoscut pe primul rând versus fișier citit până la capăt: recunoaște din enunț care dintre cele două șabloane de citire se aplică — amestecarea lor duce fie la citiri lipsă, fie la bucle care nu se opresc corect.
Strategia de verificare înainte de predare: deschide fișierul de ieșire și compară-l vizual cu formatul cerut de enunț (numărul de rânduri, separatorii); apoi testează și cazurile-limită — fișier cu un singur număr, fișier în care toate valorile sunt egale. Programele care pică testele de concurs pică aproape întotdeauna pe format sau pe cazuri-limită, nu pe algoritmul principal.
De reținut
- fișier
- colecție de date memorată pe un suport de stocare, identificată prin nume și extensie, care păstrează datele și după oprirea programului
- persistența datelor
- proprietatea datelor salvate în fișiere de a supraviețui închiderii programului și opririi calculatorului, spre deosebire de variabilele din memoria RAM
- fișier text
- fișier care conține caractere lizibile organizate pe rânduri, cu numerele scrise ca șiruri de cifre despărțite prin spații sau rânduri noi
- ifstream
- flux de citire dintr-un fișier în C++ (biblioteca fstream); se folosește cu operatorul >>, exact ca cin
- ofstream
- flux de scriere într-un fișier în C++; se folosește cu operatorul <<, exact ca cout; creează fișierul dacă nu există și îi șterge conținutul dacă există
- close()
- operația de închidere a unui fișier; la fișierele de ieșire garantează că datele din zona tampon ajung efectiv pe disc
- sfârșitul fișierului (EOF)
- momentul în care nu mai există date de citit; expresia fin >> x devine falsă, oprind natural bucla while (fin >> x)
- citire până la capăt
- șablonul while (fin >> x) folosit când numărul valorilor din fișier nu este cunoscut dinainte
- buffer (zonă tampon)
- zonă intermediară de memorie prin care trec datele scrise; explică de ce un fișier neînchis poate rămâne gol sau incomplet
Greșeli frecvente
Greșit: Rularea programului cu fișierul de intrare inexistent sau aflat în alt folder decât programul
Corect: Fișierul de intrare trebuie să existe în folderul programului (sau să fie indicat cu calea completă); altfel citirea eșuează și variabilele rămân cu valori neinițializate
Greșit: Presupunerea că deschiderea unui fișier de ieșire existent păstrează conținutul vechi
Corect: ofstream șterge la deschidere tot conținutul anterior al fișierului; scrierea începe de la zero la fiecare rulare, iar datele vechi se pierd fără avertisment
Greșit: Citirea unui număr necunoscut de valori cu o buclă care nu verifică reușita citirii
Corect: Șablonul corect pune citirea chiar în condiție: while (fin >> x); după sfârșitul fișierului, o citire cu >> nu mai umple variabila și s-ar prelucra valori rămase de la pasul anterior
Greșit: Memorarea tuturor valorilor într-un vector chiar și pentru sumă, maxim sau numărare
Corect: Aceste prelucrări se fac direct la citire, cu un acumulator; vectorul e necesar doar când valorile trebuie revizitate ulterior
Greșit: Ignorarea formatului de ieșire cerut de enunț (separatori, rânduri)
Corect: Evaluarea automată compară fișierul de ieșire caracter cu caracter; separatorii și rândurile noi se scriu exact ca în enunț, altfel răspunsul e respins chiar cu valori corecte
Test — 6 întrebări ca la examen
1. Care este motivul principal pentru care un program salvează datele într-un fișier în loc să le țină doar în variabile?
- fișierele fac programul să ruleze mai repede
- variabilele din RAM dispar la închiderea programului, iar fișierele păstrează datele pe disc
- variabilele pot memora doar numere mici
- fișierele nu pot fi șterse niciodată
Vezi răspunsul
variabilele din RAM dispar la închiderea programului, iar fișierele păstrează datele pe disc. Fișierele oferă persistență: datele supraviețuiesc închiderii programului și opririi calculatorului, pentru că stau pe disc, nu în RAM. Distractorul cu viteza e chiar inversul realității — accesul la disc e mai lent decât accesul la memorie.
2. În C++, pentru a citi date dintr-un fișier text se folosește un obiect de tip:
- ofstream, cu operatorul <<
- ifstream, cu operatorul >>
- ifstream, cu operatorul <<
- cout, cu operatorul >>
Vezi răspunsul
ifstream, cu operatorul >>. ifstream (input file stream) citește, folosind >> exact ca cin. Varianta a treia încurcă operatorii: săgețile arată sensul datelor — spre variabilă la citire (>>), dinspre variabilă la scriere (<<); ofstream și cout sunt pentru scriere, respectiv afișare.
3. Fișierul de ieșire rezultate.txt există deja și conține date de la o rulare anterioară. Ce se întâmplă la o nouă deschidere cu ofstream?
- noile date se adaugă după cele vechi
- programul se oprește cu eroare, fișierul existând deja
- conținutul vechi se șterge și scrierea începe de la zero
- conținutul vechi rămâne, iar noile date îl suprascriu doar parțial
Vezi răspunsul
conținutul vechi se șterge și scrierea începe de la zero. Deschiderea implicită cu ofstream golește fișierul existent; fiecare rulare pornește cu fișier de ieșire curat. Adăugarea la coadă (prima variantă) există ca mod special (append), dar nu e comportamentul implicit — exact confuzia pe care o testează întrebarea.
4. Fișierul de intrare conține un număr necunoscut de valori întregi. Care secvență le prelucrează corect pe toate?
- while (fin >> x) s += x;
- fin >> n; for (i = 0; i < n; i++) { fin >> x; s += x; }
- for (i = 0; i < 100; i++) { fin >> x; s += x; }
- do { fin >> x; s += x; } while (x != 0);
Vezi răspunsul
while (fin >> x) s += x;. while (fin >> x) citește cât timp mai există date și se oprește singur la sfârșitul fișierului — șablonul standard când numărul valorilor nu e cunoscut. A doua variantă presupune că n e scris în fișier (nu e cazul aici), a treia ghicește o limită, iar a patra se oprește greșit la orice valoare 0 din date.
5. Un elev scrie rezultatele cu fout, dar uită fout.close() la final, iar fișierul rămâne uneori gol. Care este explicația?
- fără close(), fișierul se șterge automat
- datele scrise trec printr-o zonă tampon, iar închiderea garantează ajungerea lor pe disc
- close() este cel care creează fișierul
- operatorul << nu funcționează fără close()
Vezi răspunsul
datele scrise trec printr-o zonă tampon, iar închiderea garantează ajungerea lor pe disc. Scrierea trece printr-un buffer; close() „împinge” pe disc tot ce a rămas în el. Fără închidere, datele pot rămâne blocate în tampon și fișierul apare gol sau incomplet. Fișierul e creat la deschidere, nu de close() — distractorul al treilea inversează momentele.
6. Fișierul de intrare conține: 4 pe primul rând și 10 20 30 40 pe al doilea. Ce afișează: fin >> n; s = 0; for (i = 1; i <= n; i++) { fin >> x; s += x; } cout << s;?
- 104
- 100
- 96
- 4
Vezi răspunsul
100. Primul număr citit este n = 4, apoi se citesc și se adună exact 4 valori: 10 + 20 + 30 + 40 = 100. Distractorul 104 apare la cine crede că și n intră în sumă, iar 4 la cine oprește citirea după primul rând — operatorul >> nu ține cont de rânduri, ci doar de ordinea valorilor.
Deschide varianta interactivă — cu AI care îți explică