Programmare in C – File binari

I file binari sono molto simili ad array di strutture, eccetto per il fatto che le strutture si trovano in un array in memoria e non su disco fisso.

Poiché le strutture possono essere “binarizzate” per essere memorizzate su un disco, si possono creare grandi collezioni di questi oggetti. Il limite della dimensione del disco fisso. Inoltre, le strutture binarizzate sono permanenti e sempre disponibili. L'unico svantaggio è la lentezza che deriva dal tempo maggiore di accesso al disco piuttosto che alla RAM.

I file binari hanno due caratteristiche che permette di distinguerli dai file di testo
• si può passare da una struttura all'altra nel file, poiché viene fornito l'accesso casuale come se si trattasse di un array
• si può cambiare il contenuto di una struttura in qualsiasi momento e in qualsiasi punto del file.

I file binari hanno generalmente operazioni di lettura e di scrittura molto più veloci rispetto ai file di testo, perchè un'immagine binaria del record viene memorizzato direttamente dalla memoria al disco e viceversa. Nel file di testo, tutto deve essere convertito e ciò richiede tempo.

Il linguaggio C supporta la struttura di file molto linearmente. Una volta che si apre il file si può leggere una struttura, scrivere una struttura, o cercare una struttura nel file. Questo concetto di gestione dei file è analogo al concetto di puntatore a file. Quando il file è aperto, il puntatore punta al record 0, il primo record nel file.

Ogni operazione di lettura fa sì che a partire dalla posizione corrente del puntatore, questo si muove avanti nella struttura. Una operazione di scrittura scrive sulla posizione corrente e sposta avanti il puntatore. La funzione seek sposta il puntatore sul record richiesto.

Ricordarsi che il C pensa a ciò che sta sul disco fisso come blocchi di bytes da leggere in memoria o da leggere dalla memoria sul disco. Il C usa puntatori a file, ma può puntare a qualsiasi byte nel file. E' il programmatore che deve tenere traccia di dove si trova il puntatore.

Il programma seguente illustra questi concetti:

#include <stdio.h>

/* Descrizione della struttura a 
record casuale – potrebbe 
essere qualsiasi cosa */
struct rec
{
    int x,y,z;
};

/* scrive e legge 10 records 
a caso dal file junk. */
int main()
{
    int i,j;
    FILE *f;
    struct rec r;

    /* crea il file di 10 records */
    f=fopen("junk","w");
    if (!f)
        return 1;
    for (i=1;i<=10; i++)
    {
        r.x=i;
        fwrite(&r,sizeof(struct rec),1,f);
    }
    fclose(f);

    /* legge i 10 records */
    f=fopen("junk","r");
    if (!f)
        return 1;
    for (i=1;i<=10; i++)
    {
        fread(&r,sizeof(struct rec),1,f);
        printf("%d\n",r.x);
    }
    fclose(f);
    printf("\n");

    /* usa la funzione fseek 
per leggere  10 records
       in ordine inverso */
    f=fopen("junk","r");
    if (!f)
        return 1;
    for (i=9; i>=0; i--)
    {
        fseek(f,sizeof(struct rec)*i,SEEK_SET);
        fread(&r,sizeof(struct rec),1,f);
        printf("%d\n",r.x);
    }
    fclose(f);
    printf("\n");

    /* usa fseek per leggere gli altri  record */
    f=fopen("junk","r");
    if (!f)
        return 1;
    fseek(f,0,SEEK_SET);
    for (i=0;i<5; i++)
    {
        fread(&r,sizeof(struct rec),1,f);
        printf("%d\n",r.x);
        fseek(f,sizeof(struct rec),SEEK_CUR);
    }
    fclose(f);
    printf("\n");

    /* usa fseek per leggere il 4* record,
       modificarlo, e sovrascriverlo */
    f=fopen("junk","r+");
    if (!f)
        return 1;
    fseek(f,sizeof(struct rec)*3,SEEK_SET);
    fread(&r,sizeof(struct rec),1,f);
    r.x=100;
    fseek(f,sizeof(struct rec)*3,SEEK_SET);
    fwrite(&r,sizeof(struct rec),1,f);
    fclose(f);
    printf("\n");

    /* leggere i 10 records 
per assicurarsi che il 
       4th record sia stato cambiato */
    f=fopen("junk","r");
    if (!f)
        return 1;
    for (i=1;i<=10; i++)
    {
        fread(&r,sizeof(struct rec),1,f);
        printf("%d\n",r.x);
    }
    fclose(f);
    return 0;
}

In questo programma, è stata usata una descrizione senza troppi significati della struttura rec, si può usare però qualsiasi struttura.
Le funzioni fopen e fclose funzionano esattamente allo stesso modo che nei file di testo.

Le nuvoe funzioni sono fread, fwrite e fseek.
La funzione fread accetta in input 4 parametri:
• un indirizzo di memoria
• il numero di byte da leggere per blocco,
• il numero di blocchi da leggere
• la variabile del file

Quindi, la linea fread(&r,sizeof(struct rec),1,f); significa che si devono leggere 12 byte (/ la dimensione di rec) dal file f – dalla posizione corrente del puntatore e immetterlo nell'indirizzo di memoria &r. Un blocco di 12 bytes viene pertanto letto.

La funzione fwrite lavora nello stesso modo, ma sposta i blocchi di bytes dalla memoria al file. La funzione fseek sposta il puntaore del file su di un byte nel file. Generalmente si fa muovere il puntatore della dimensione della struttura (sizeof(struct rec)). Durante le operazioni di spostamento del puntatore con la funzione fseek si possono utilizzare le seguenti opzioni:
• SEEK_SET
• SEEK_CUR
• SEEK_END

SEEK_SET sposta il puntatore di x byte prima dell'inizio del file (a partire dal byte 0 del file)
SEEK_CUR sposta il puntatore di x bytes dalla posizione corrente
SEEK_END sposta il puntatore dalla fine del file (e si deve pertanto usare un offset negativo con questa opzione)

Altre opzioni diverse si possono trovare nel codice precedente. In particolare, è da notare che il file viene aperto in modalità r+, ossia viene aperto per lettura e scrittura e di conseguenza i record possono essere modificati.

Il codice sopra, cerca un record, lo legge e cambia il valore di un campo. Poi, si sposta all'indietro perchè la lettura precedente ha cambiato la posizione del puntatore e scrive i cambiamenti apportati.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend