De ce contează?
Până acum ai „vorbit” cu programul prin tastatură și ecran: tu scrii numerele, el îți răspunde pe loc. Dar la concurs nimeni nu stă să tasteze — datele te așteaptă deja scrise într-un fișier. Imaginează-ți un caiet în care întrebarea e pe prima pagină: programul îl deschide, citește datele, calculează în liniște și notează răspunsul pe ultima pagină, singur. Exact așa lucrează un program cu fișiere text.
Intuiția
Un fișier text este pur și simplu un fișier în care datele sunt scrise ca text obișnuit, exact ca ce ai tasta tu. Programul îl tratează ca pe un flux (stream): citește din el cuvânt cu cuvânt, de la stânga la dreapta, la fel cum cin citea de la tastatură. Diferența e doar de unde vin datele și unde merge rezultatul: nu de la tastatură și pe ecran, ci dintr-un fișier și într-un alt fișier.
Ce este
Pentru fișiere, C++ îți dă două „unelte” din biblioteca <fstream>:
ifstream— input file stream, fluxul prin care citești dintr-un fișier (joacă rolul luicin).ofstream— output file stream, fluxul prin care scrii într-un fișier (joacă rolul luicout).
Le folosești exact ca pe cin și cout: cu >> citești din ifstream, cu << scrii în ofstream. Singura noutate e că la început deschizi fișierul (îi dai numele) și la final e bine să-l închizi.
De ce cer concursurile citire din fișier? Pentru că evaluatorul testează sute de soluții automat: pune datele de test într-un fișier (de obicei date.in), rulează programul tău, apoi compară ce ai scris în date.out cu răspunsul corect. Nimeni nu stă să tasteze la mână. Numele fișierelor sunt impuse în enunț — dacă scrii în alt fișier, ai punctaj zero, chiar dacă algoritmul e perfect.
Cum arată
Să zicem că enunțul cere: pe prima linie din date.in se află n (câte numere urmează), apoi cele n numere. Programul trebuie să scrie suma lor în date.out.
Conținutul fișierului de intrare:
date.in
5
4 9 7 1 3Aici n = 5, deci urmează 5 numere: 4, 9, 7, 1, 3. Programul le adună (4+9+7+1+3 = 24) și produce:
date.out
244 | 9 | 7 | 1 | 3 |
0 | 1 | 2 | 3 | 4 |
Observă: în date.in numerele sunt separate prin spații (sau prin linii noi — pentru >> nu contează). Operatorul de citire sare automat peste spații și treceri la linie nouă, exact ca cin.
Implementare C++
Citim n, apoi n numere, le adunăm și scriem suma în fișierul de ieșire:
#include <fstream>
using namespace std;
int main() {
// deschidem fisierul de intrare si pe cel de iesire
ifstream fin("date.in");
ofstream fout("date.out");
int n;
fin >> n; // citim cate numere urmeaza
int suma = 0;
for (int i = 0; i < n; i++) {
int x;
fin >> x; // citim al i-lea numar din fisier
suma += x; // il adaugam la suma
}
fout << suma << "\n"; // scriem rezultatul in date.out
// inchidem fisierele: golim ce a ramas in buffer pe disc
fin.close();
fout.close();
return 0;
}Citește-l ca pe cin/cout, doar că în loc de cin ai fin și în loc de cout ai fout. Restul logicii — bucla, suma — e identică.
Citirea până la EOF
Uneori enunțul NU îți dă n — fișierul conține doar un șir de numere și trebuie să le citești pe toate, până se termină. Aici folosești faptul că o operație de citire eșuează când nu mai are ce citi (a ajuns la EOF, end of file). Poți pune chiar citirea drept condiție:
#include <fstream>
using namespace std;
int main() {
ifstream fin("date.in");
ofstream fout("date.out");
int suma = 0, x;
// cat timp inca reusim sa citim un numar, il adunam
while (fin >> x) {
suma += x;
}
fout << suma << "\n";
fin.close();
fout.close();
return 0;
}fin >> x întoarce fluxul însuși, iar acesta e „adevărat” cât timp citirea a reușit și devine „fals” când s-a atins sfârșitul fișierului. Așa bucla se oprește singură, fără să știi dinainte câte numere sunt.
Există și freopen("date.in", "r", stdin): el „redirectează” tastatura către fișier, ca să poți scrie mai departe cin și cout ca de obicei. E perfect valid la concurs. Avantajul lui ifstream/ofstream e claritatea — vezi negru pe alb din ce flux citești și în care scrii.
Trei capcane care îți pierd punctajul deși algoritmul e corect:
- Numele fișierului greșit. Enunțul cere
date.in, tu scriiDate.in,date.txtsaudate.in(cu spațiu). Programul deschide un fișier gol, citește zerouri și răspunde aiurea. Copiază numele EXACT din enunț. - Folosești
cin/coutîn loc defin/fout. După ce ai deschis fișierele, dacă din reflex scriicin >> x, citești de la tastatură — adică din nimic, la evaluare. Tot ce iese din fișier trebuie să treacă prinfinșifout. - Uiți să închizi (sau să golești) fișierul de ieșire. Ce scrii cu
fout <<stă întâi într-un buffer;fout.close()(sau ieșirea normală dinmain) îl scrie pe disc. Dacă programul se termină brusc, fără să închidă,date.outpoate rămâne gol.