Vai al contenuto

La gestione dei file

Scrittura, lettura e modifica di file di testo e binari con la libreria .

La gestione dei file in C++ è fondamentale per salvare e recuperare dati da supporti esterni. Utilizzando la libreria <fstream>, è possibile eseguire operazioni di lettura, scrittura e modifica dei file in modo semplice ed efficiente.

🎯 Perché usare i file? Persistenza dei dati, condivisione di informazioni, backup e configurazioni dell'applicazione

1. Classi Principali della Libreria <fstream>

📌 Le tre classi fondamentali: Tutte ereditano da <iostream> e offrono metodi per controllare il flusso dei dati

O ofstream

Stream di output per scrivere su file

Creazione e modifica file

ofstream fileOut("nome.txt");

I ifstream

Stream di input per leggere da file

Lettura e elaborazione dati

ifstream fileIn("nome.txt");

F fstream

Stream bidirezionale

Lettura e scrittura sullo stesso file

fstream fileIO("nome.txt");

2. Scrittura su File con ofstream

📌 Procedura di scrittura: Creazione oggetto → Apertura file → Verifica → Scrittura dati → Chiusura file

2.1 Esempio di Scrittura Base

#include <iostream>
#include <fstream>
using namespace std;

int main() {
    // Creazione di un oggetto ofstream per scrivere su file
    ofstream fileOut("dati.txt");

    // Verifica dell'apertura del file
    if (!fileOut) {
        cerr << "Errore nell'apertura del file per la scrittura." << endl;
        return 1;
    }

    // Scrittura di dati su file
    fileOut << "Ciao, questo è un esempio di scrittura su file." << endl;
    fileOut << "Linea 2: gestione dei file in C++." << endl;

    // Chiusura del file
    fileOut.close();

    cout << "Dati scritti correttamente su 'dati.txt'." << endl;
    return 0;
}

💡 Spiegazione: • Creazione oggetto: ofstream fileOut("dati.txt") crea e apre il file • Controllo errori: if (!fileOut) verifica se l'apertura è riuscita • Scrittura: Si usa l'operatore << come con cout • Chiusura: close() libera le risorse

3. Lettura da File con ifstream

📌 Procedura di lettura: Apertura file → Verifica → Lettura riga per riga → Elaborazione → Chiusura

3.1 Esempio di Lettura Base

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
    ifstream fileIn("dati.txt");

    // Verifica dell'apertura del file
    if (!fileIn) {
        cerr << "Errore nell'apertura del file per la lettura." << endl;
        return 1;
    }

    string riga;
    // Lettura del file riga per riga
    while (getline(fileIn, riga)) {
        cout << riga << endl;
    }

    // Chiusura del file
    fileIn.close();

    return 0;
}

💡 Spiegazione: • getline(): Legge una riga intera fino al carattere di newline • Controllo fine file: Il ciclo while si ferma automaticamente a EOF • Alternative: Si può usare anche fileIn >> per leggere parole singole

4. Operazioni Bidirezionali con fstream

🎭 Modalità di apertura: Combina diverse flag per controllare il comportamento del file

4.1 Flag di Apertura Comuni

I ios::in

Apertura in lettura

File deve esistere

O ios::out

Apertura in scrittura

Crea file se non esiste

T ios::trunc

Cancella contenuto esistente

File vuoto

A ios::app

Scrittura in append

Mantiene contenuto esistente

4.2 Esempio di Lettura e Scrittura

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
    // Apertura del file in modalità lettura e scrittura
    fstream file("dati_bidirezionale.txt", ios::in | ios::out | ios::trunc);

    if (!file) {
        cerr << "Errore nell'apertura del file." << endl;
        return 1;
    }

    // Scrittura di dati sul file
    file << "Linea 1: Dati iniziali." << endl;
    file << "Linea 2: Continuazione dei dati." << endl;

    // Per leggere il contenuto, è necessario riposizionare il cursore all'inizio
    file.seekg(0);

    string contenuto;
    cout << "Contenuto del file:" << endl;
    while (getline(file, contenuto)) {
        cout << contenuto << endl;
    }

    file.close();
    return 0;
}

💡 Spiegazione: • Combination flag: ios::in | ios::out | ios::trunc combina più modalità • seekg(0): Riposiziona il cursore di lettura all'inizio del file • Operazioni miste: Possibile alternare lettura e scrittura sullo stesso file

5. Esercizio Pratico: Rubrica di Contatti

🎯 Obiettivo: Creare un programma che chieda all'utente di inserire contatti, salvi i dati in un file di testo e legga il file visualizzando tutti i contatti

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

struct Contatto {
    string nome;
    string telefono;
};

int main() {
    int n;
    cout << "Quanti contatti vuoi inserire? ";
    cin >> n;
    cin.ignore(); // Pulisce il buffer

    // Creazione del file in modalità scrittura
    ofstream rubricaOut("rubrica.txt");
    if (!rubricaOut) {
        cerr << "Errore nell'apertura del file per la scrittura." << endl;
        return 1;
    }

    Contatto contatto;
    for (int i = 0; i < n; i++) {
        cout << "\nInserisci il nome del contatto " << i + 1 << ": ";
        getline(cin, contatto.nome);
        cout << "Inserisci il numero di telefono: ";
        getline(cin, contatto.telefono);
        // Scrive il contatto nel file, separando i campi con una virgola
        rubricaOut << contatto.nome << "," << contatto.telefono << endl;
    }
    rubricaOut.close();

    // Lettura e visualizzazione dei contatti dal file
    ifstream rubricaIn("rubrica.txt");
    if (!rubricaIn) {
        cerr << "Errore nell'apertura del file per la lettura." << endl;
        return 1;
    }

    cout << "\n--- Rubrica dei Contatti ---" << endl;
    string linea;
    while (getline(rubricaIn, linea)) {
        cout << linea << endl;
    }

    rubricaIn.close();
    return 0;
}

💡 Caratteristiche dell'esercizio: • Struct Contatto: Organizza i dati in modo strutturato • cin.ignore(): Pulisce il buffer dopo cin >> • Formato CSV: Campi separati da virgola per una facile elaborazione • Doppia operazione: Scrittura e successiva lettura dello stesso file

6. Esercizio Avanzato: Registro delle Presenze

🎯 Obiettivo: Implementa un programma che registri le presenze degli studenti, salvi i dati in un file, calcoli e visualizzi il totale delle presenze

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

struct Presenza {
    string nomeStudente;
    bool presente; // true = presente, false = assente
};

int main() {
    int n;
    cout << "Quanti studenti vuoi registrare? ";
    cin >> n;
    cin.ignore();

    ofstream registroOut("registro_presenze.txt");
    if (!registroOut) {
        cerr << "Errore nell'apertura del file per la scrittura." << endl;
        return 1;
    }

    Presenza studente;
    for (int i = 0; i < n; i++) {
        cout << "\nInserisci il nome dello studente " << i + 1 << ": ";
        getline(cin, studente.nomeStudente);

        char risposta;
        cout << "Lo studente è presente? (s/n): ";
        cin >> risposta;
        cin.ignore();
        studente.presente = (risposta == 's' || risposta == 'S');

        // Salva il record nel file
        registroOut << studente.nomeStudente << "," << (studente.presente ? "Presente" : "Assente") << endl;
    }
    registroOut.close();

    // Lettura del registro e calcolo del totale delle presenze
    ifstream registroIn("registro_presenze.txt");
    if (!registroIn) {
        cerr << "Errore nell'apertura del file per la lettura." << endl;
        return 1;
    }

    int totalePresenze = 0;
    string record;
    cout << "\n--- Registro Presenze ---" << endl;
    while (getline(registroIn, record)) {
        cout << record << endl;
        // Se il record contiene "Presente", incrementa il contatore
        if (record.find("Presente") != string::npos) {
            totalePresenze++;
        }
    }
    registroIn.close();

    cout << "\nTotale presenze: " << totalePresenze << endl;
    return 0;
}

💡 Caratteristiche dell'esercizio: • Input interattivo: L'utente inserisce dati dinamicamente • Conversione bool: Trasforma risposta s/n in valore booleano • Operatore ternario: condizione ? vero : falso per scegliere il testo • string::find(): Cerca sottostringhe per contare le presenze

7. Best Practices e Consigli

Regole fondamentali:

Controllo Errori

Verifica sempre se il file è stato aperto correttamente con if (!file)

Chiusura File

Chiudi sempre il file con close() per liberare risorse

Gestione Buffer

Usa cin.ignore() dopo cin >> per pulire il buffer

Modalità Appropriate

Scegli le flag giuste (ios::app, ios::trunc) per ogni operazione

Formato Dati

Usa separatori consistenti (virgole, punti e virgola) per file strutturati

Conclusioni

Punti chiave della gestione file:

ofstream

Per scrivere dati su file, creazione e modifica contenuti

ifstream

Per leggere dati da file, elaborazione e analisi

fstream

Per operazioni bidirezionali, lettura e scrittura combinate

Applicazioni Pratiche

Rubriche, registri, configurazioni, salvataggio dati applicazione

La gestione dei file con <fstream> in C++ consente di interagire con dati esterni in modo semplice ed efficiente. Attraverso gli esempi sopra riportati è possibile gestire dati strutturati, applicare best practices per evitare errori e creare applicazioni che persistono i dati tra diverse esecuzioni. Buon coding! 🚀

Esercitazioni Pratiche C++

Metti in pratica ciò che hai imparato con queste esercitazioni complete

Tutte le Esercitazioni

📊 Variabili e Tipi di Dato

➕ Operatori Matematici e Logici in C++

🔀 Strutture di controllo condizionali

🔄 I cicli in C++

🗃️ C++ gli array

⚙️ Le funzioni in C++

📈 Ordinamento dei Dati

🏗️ Le struct in C++

🎯 I puntatori

🧩 La Programmazione Orientata agli Oggetti (OOP)

📁 La gestione dei file in C++

💪 Esercizi C++ Raccolta Completa

12 esercitazioni complete per padroneggiare il C++