File in C

In questa lezione impariamo a leggere e scrivere su file in C

Cos’è un File

Un file è una struttura con cui vengono archiviate le informazioni nel computer. La relazione di scienze che scrivi con word è un file, così come la presentazione di storia e gli stessi programmi in c che trattiamo qui. I file vengono salvati nella memoria di massa, motivo per cui rimangono presenti anche dopo aver spento il computer.

Poiché possono contenere informazioni di svariato tipo come immagini, video, testo, codice e molto altro, i file possiedono un’estensione diversa a seconda del loro contenuto. Si possono comunque identificare in due categorie: file di testo e binari. I primi sono comprensibili da un essere umano, mentre gli ultimi lo sono da un computer. La compilazione di un programma C contiene un buon esempio.

tipi file

Operazioni su File

Un programma è in grado di effettuare due operazioni principali su un file: lettura e scrittura. Per fare questo apre uno stream, o flusso, di dati che permette di accedere al contenuto del file tramite il sistema operativo. Una volta terminata l’operazione di lettura o scrittura, lo stream viene chiuso.

stream file

Quando, per esempio, apri un documento word stai leggendo un file, quando invece fai una modifica e lo salvi stai effettuando una scrittura su file.

Operazioni su file in C

In C è possibile leggere o scrivere su file con la funzione fopen(), che apre uno stream e ritorna un puntatore di tipo FILE. Una volta terminata l’operazione è necessario chiudere lo stream con fclose().

fopen ha due parametri: il primo è il percorso del file nel computer e il secondo è il tipo di operazione da effettuare. Tra le operazioni possibili abbiamo:

  • r“: lettura di un file
  • w“: scrittura su file, se il file non esiste viene creato
  • a“: append su file (scrittura su file senza eliminare il contenuto già presente)
// Apro uno stream sul file prova.txt

FILE *fp = fopen("prova.txt","r");

// fp ora punta all'inizio del file e man mano che leggo il contenuto raggiungerà la fine

//chiudo lo stream
fclose(fp);

Attenzione alla differenza tra “w” ed “a“. Se il file è già esistente il primo eliminerà tutto il suo contenuto prima di scrivere, mentre il secondo appenderà la scrittura alla fine del file.

Per non raggiungere la fine del file mentre si legge, si può utilizzare la funzione feof(), che ritorna un numero diverso da zero se la fine del file è stata raggiunta.

//Finchè non raggiungo la fine del file

while( feof( fp ) == 0 ){
    //leggi il contenuto del file
}

File di testo

Per leggere e scrivere su file di testo utilizziamo le funzioni fscanf() e fprintf(). Come potrai immaginare, la sintassi di queste funzioni è molto simile a quella di scanf() e printf(). Entrambe ritornano il numero di elementi letti.

fscanf fprintf

Qui sotto trovi un programma di esempio che legge il contenuto di un file.

#include <stdio.h>

int main(){

    //Leggo il file numeri.txt
    FILE *fp = fopen("numeri.txt", "r");

    int numeroLetto;

    //Se il file è stato aperto, e quindi esiste, comincio a leggere
    if( fp != NULL ){

        //Leggo finchè non raggiungo la fine del file
        while( feof(fp) == 0 ){
        //Leggo un numero e un ritorno a capo, salvo il numero in numeroLetto
        fscanf( fp, "%d\n", &numeroLetto );

        //Stampo il valore di numeroLetto
        printf("Letto il numero %d \n", numeroLetto);
        }
        fclose(fp);
    }
    else {
        printf("File non trovato");
    }

return 0;
}

Utilizzando il seguente file:

file testo

Otterrò questo risultato in output:

Letto il numero 10
Letto il numero 20
Letto il numero 50
Letto il numero 30
Letto il numero 40

File binari

Per leggere e scrivere su file binari utilizziamo invece le funzioni fread() e fwrite(), che ritornano il numero di elementi letti.

fread fwrite

Proviamo a scrivere due programmi, uno per scrivere una serie di numeri su file binario e uno per leggerli.

#include <stdio.h>

int main(){

    //Scrivo sul file numeri.bin
    FILE *fp = fopen("numeri.bin", "w");

    int numeri[5];
    numeri[0] = 10;
    numeri[1] = 20;
    numeri[2] = 30;
    numeri[3] = 40;
    numeri[4] = 50;


    //Se il file è stato creato comincio a scrivere
    if( fp != NULL ){

        //Scrivo tutti i numeri
        int elementiScritti = fwrite( numeri, sizeof(int), 5, fp);

        fclose(fp);

        if( elementiScritti != 5 ){
        printf("Errore nella scrittura\n");
        }
    }
    else {
        printf("Errore nell'apertura del file\n");
    }

return 0;
}
#include <stdio.h>

int main(){

    //Scrivo sul file numeri.bin
    FILE *fp = fopen("numeri.bin", "r");

    int numeri[5];


    //Se il file è stato creato comincio a scrivere
    if( fp != NULL ){

        //Scrivo tutti i numeri
        int elementiScritti = fread( numeri, sizeof(int), 5, fp);

        fclose(fp);

        if( elementiScritti != 5 ){
        printf("Errore nella lettura\n");
        }
        else{
            int i=0;
            for(i=0; i<5; i++){
                printf("Numero letto: %d\n", numeri[i]);
            }
        }
    }
    else {
        printf("Errore nell'apertura del file\n");
    }

return 0;
}

Eseguendo il primo programma scriviamo 5 numeri sul file numeri.bin, nel secondo invece li andiamo a leggere ottenendo il seguente output:

Numero Letto: 10
Numero Letto: 20
Numero Letto: 30
Numero Letto: 40
Numero Letto: 50

Aprendo il file però non ci troviamo davanti dei numeri, ma dei caratteri poco comprensibili: Abbiamo scritto un file binario.

file binario

I file binari ci risultano molto utili quando dobbiamo salvare grandi quantità di informazioni o strutture complesse. Immaginiamo di dover salvare su file delle informazioni anagrafiche sugli alunni di una scuola.

struct alunno{
  char[50] nome;
  char[50] cognome;
  char sesso;
  char[16] codiceFiscale;
  char[5] classe;
  struct data dataNascita;
};

struct data{
  int giorno;
  int mese;
  int anno;
};

Per salvare un array di alunni in un file di testo dovremmo scomporre la struttura nei suoi elementi con tipo semplice, mentre con i file binari possiamo salvare la struttura così com’è.