MORENO SARDELLA · CORSO BASE
← Tutte le lezioni
Lezione 9

I FILE DI TESTO

Quando il programma si chiude, tutte le variabili spariscono. Ma se voglio salvare i dati per ritrovarli domani? Servono i file: una memoria permanente su disco.

01
Perché servono

Memoria che resta

Variabili, vettori e matrici vivono nella RAM: spariscono appena il programma termina (memoria volatile). Un file è salvato su disco e resta anche dopo: lo puoi rileggere alla prossima esecuzione, condividere, modificare.

RAM (variabili) v[ ] m[ ][ ] si svuota a fine programma FILE (su disco) dati.txt voti.csv resta nel tempo
La RAM è temporanea; il file è permanente. Ecco perché si salva su file.

Inoltre un file può contenere tanti dati e di numero variabile: non devi sapere in anticipo quante righe ci sono, le leggi finché non finiscono.

02
In C++

ifstream e ofstream

Con #include <fstream>: ofstream per scrivere (output) e ifstream per leggere (input). La cosa comoda è che si usano esattamente come cout e cin, con gli stessi operatori << e >>. Ricordati sempre di controllare l'apertura e di chiudere il file.

Scrivere con <<

Un ofstream con l'operatore << funziona come cout: il testo, invece che a schermo, finisce nel file. Puoi scrivere numeri, stringhe e separatori.

scrivi.cpp
#include <fstream>
ofstream fout("dati.txt");
fout << 1 << " " << "Ba" << endl;        // scrive: 1 Ba
fout << 2 << " " << "Citrulo" << endl;   // scrive: 2 Citrulo
fout.close();

Leggere con >>

Un ifstream con l'operatore >> funziona come cin: legge un valore alla volta, saltando automaticamente spazi e a-capo. È perfetto per i file con campi separati da spazi. Il ciclo while (fin >> …) continua finché ci sono dati da leggere.

Per esempio, dato il file dati.txt con un numero e un nome per riga:

1 Ba 2 Citrulo
leggi.cpp
ifstream fin("dati.txt");
if (!fin) { cout << "Errore nell'apertura del file"; return 1; }

int numero; string nome;
while (fin >> numero >> nome) {     // legge il numero, poi il nome
    cout << "Numero: " << numero << " - Nome: " << nome << endl;
}
fin.close();
Attenzione — l'operatore >> si ferma al primo spazio, quindi legge una parola alla volta: va benissimo per 1 Ba, ma un nome con spazi (es. Anna Bianchi) verrebbe spezzato in due. In quel caso serve getline.

Leggere intere righe con getline

Quando una riga contiene spazi (una frase, un nome e cognome), >> si fermerebbe al primo spazio. Allora si usa getline, che legge l'intera riga in una stringa.

righe.cpp
ifstream fin("diario.txt");
string riga;
while (getline(fin, riga))        // una riga intera alla volta
    cout << riga << endl;
fin.close();
03
Dati strutturati

I file CSV

Un CSV (Comma-Separated Values) è un file di testo dove ogni riga è un record e i campi sono separati da virgole. È il formato con cui si scambiano tabelle (lo aprono anche Excel e Google Fogli): perfetto per salvare un vettore di struct.

Giulia,7.5 Marco,6.0 Sara,8.5 nome voto
Un CSV "voti.csv": ogni riga è nome,voto — la virgola separa i campi.
leggi_csv.cpp
#include <fstream>
#include <string>

ifstream fin("voti.csv");
if (!fin) { cout << "File non trovato"; return 1; }

string riga;
while (getline(fin, riga)) {        // una riga alla volta
    int pos = riga.find(',');       // posizione della virgola
    string nome = riga.substr(0, pos);
    float voto = stof(riga.substr(pos + 1));
    cout << nome << " ha preso " << voto << endl;
}
fin.close();
Scrivere un CSV — basta separare i campi con la virgola: fout << nome << "," << voto << endl; per ogni record del tuo vettore di struct.

04
Esercizi

Gli esercizi

Base: scrivere e leggere file .txt, .dat e .csv. Avanzati: i file legati a vettori, matrici e struct (salvataggio e caricamento di record). 10 esercizi ciascuna.

File — basescarica ↓
File — avanzatiscarica ↓
Soluzioni · File base
1 — Scrivi su txt void scriviRighe(string nomeFile, const int N){ ofstream fout(nomeFile); cin.ignore(); for(int i=0;i<N;i++){ string r; getline(cin,r); fout<<r<<endl; } fout.close(); }
2 — Leggi un txt void stampaFile(string nomeFile){ ifstream fin(nomeFile); if(!fin){ cout<<"Errore"; return; } string r; while(getline(fin,r)) cout<<r<<endl; fin.close(); }
3 — Conta righe int contaRighe(string nomeFile){ ifstream fin(nomeFile); string r; int n=0; while(getline(fin,r)) n++; fin.close(); return n; }
4 — Numeri su dat // << per scrivere, >> per leggere void scriviNumeri(string nomeFile, int v[], const int N){ ofstream fout(nomeFile); for(int i=0;i<N;i++) fout<<v[i]<<" "; fout.close(); } int sommaDaFile(string nomeFile){ ifstream fin(nomeFile); int x, s=0; while(fin>>x) s+=x; // >> un numero alla volta fin.close(); return s; }
5 — Copia file void copiaFile(string orig, string dest){ ifstream fin(orig); ofstream fout(dest); string r; while(getline(fin,r)) fout<<r<<endl; fin.close(); fout.close(); }
6 — Cerca una parola int contaOccorrenze(string nomeFile, string parola){ ifstream fin(nomeFile); string p; int c=0; while(fin>>p) if(p==parola) c++; // >> parola per parola fin.close(); return c; }
7 — Crea un CSV void scriviCsv(string nomeFile, const int N){ ofstream fout(nomeFile); for(int i=0;i<N;i++){ string nome; float voto; cin>>nome>>voto; fout<<nome<<","<<voto<<endl; } fout.close(); }
8 — Leggi un CSV // getline + find/substr void leggiCsv(string nomeFile){ ifstream fin(nomeFile); string r; while(getline(fin,r)){ int pos=r.find(','); cout<<r.substr(0,pos)<<" -> "<<r.substr(pos+1)<<endl; } fin.close(); }
9 — Conta record CSV int contaRecord(string nomeFile){ ifstream fin(nomeFile); string r; int n=0; while(getline(fin,r)) n++; fin.close(); return n; }
10 — Aggiungi in coda void aggiungiRiga(string nomeFile, string riga){ ofstream fout(nomeFile, ios::app); // modalita' append fout<<riga<<endl; fout.close(); }
Soluzioni · File avanzati
1 — Vettore su dat // << e >> void salvaVettore(string nomeFile, int v[], const int N){ ofstream fout(nomeFile); for(int i=0;i<N;i++) fout<<v[i]<<" "; fout.close(); } int caricaVettore(string nomeFile, int v[]){ ifstream fin(nomeFile); int n=0; while(fin>>v[n]) n++; // >> finche' ci sono numeri fin.close(); return n; }
2 — Matrice su file void salvaMatrice(string nomeFile, int m[][C], const int R){ ofstream fout(nomeFile); for(int i=0;i<R;i++){ for(int j=0;j<C;j++) fout<<m[i][j]<<" "; fout<<endl; } fout.close(); } void caricaMatrice(string nomeFile, int m[][C], const int R){ ifstream fin(nomeFile); for(int i=0;i<R;i++) for(int j=0;j<C;j++) fin>>m[i][j]; fin.close(); }
3 — Struct su CSV struct Studente { string nome; float voto; }; void salvaCsv(string nomeFile, Studente s[], const int N){ ofstream fout(nomeFile); for(int i=0;i<N;i++) fout<<s[i].nome<<","<<s[i].voto<<endl; fout.close(); }
4 — Media da CSV int caricaCsv(string nomeFile, Studente s[]){ ifstream fin(nomeFile); string r; int n=0; while(getline(fin,r)){ int pos=r.find(','); s[n].nome=r.substr(0,pos); s[n].voto=stof(r.substr(pos+1)); n++; } fin.close(); return n; } float media(Studente s[], const int N){ float tot=0; for(int i=0;i<N;i++) tot+=s[i].voto; return tot/N; }
5 — Esporta i promossi void salvaPromossi(string nomeFile, Studente s[], const int N){ ofstream fout(nomeFile); for(int i=0;i<N;i++) if(s[i].voto>=6) fout<<s[i].nome<<","<<s[i].voto<<endl; fout.close(); }
9 — Unisci due CSV void unisciCsv(string f1, string f2, string dest){ ofstream fout(dest); string r; ifstream a(f1); while(getline(a,r)) fout<<r<<endl; a.close(); ifstream b(f2); while(getline(b,r)) fout<<r<<endl; b.close(); fout.close(); }

Gli esercizi 6, 7, 8, 10 (classifica ordinata, report statistico, conteggio per genere, aggiorna magazzino) combinano questi stessi schemi: caricaCsv in un vettore di struct, elaborazione e salvaCsv.