prof. Nunzio Brugaletta | Programmazione e linguaggio C |
Le strutture dati trattate fino a questo punto, prevedono la registrazione degli elementi su locazioni di memoria centrale. La memoria centrale, in ragione delle sue caratteristiche, si presta a due tipi di utilizzo:
Per la sua limitatezza è opportuno utilizzarla per la conservazione dei dati strettamente indispensabili per l’elaborazione in corso.
Per la sua volatilità consente di conservare i dati limitatamente al solo tempo di esecuzione di un programma.
Se si vogliono conservare grandi quantità di dati e utilizzarli in tempi diversi, è necessario affidarsi a supporti permanenti che non hanno le limitazioni della memoria centrale: sono quelli che comunemente sono chiamate memorie di massa.
Nell’esempio successivo si gestiranno una serie di libri, conservandone in un file su memoria di massa i dati. I dati sui libri saranno registrati uno di seguito all’altro: quando si tratterà di rileggerli, l’ordine di reperimento delle informazioni sarà lo stesso di quello che si è utilizzato per la scrittura. I dati saranno quindi elaborati in maniera sequenziale.
/* Gestione File sequenziale */ #include <stdio.h> /* Definizione record */ typedef struct rec { char titolo[50]; char autore[20]; char editore[20]; float prezzo; }libro; /* Funzioni per la gestione del file */ void inserisci(); void esamina(); main(){ int scelta; for(;;){ /* Menu operazioni disponibili */ printf("\nGestione di un file contenente libri\n"); printf("\n1) Inserimento di un libro nel file"); printf("\n2) Esame dei libri contenuti nel file"); printf("\n0) Fine elebaorazione\n"); printf("\nScelta operazione (1..2,0) "); scanf("%d",&scelta); while(!getchar()=='\n'); if(!scelta) break; /* Richiama funzione scelta */ switch(scelta){ case 1: inserisci(); break; case 2: esamina(); } } return 0; } /* Inserimento di un libro nel file */ void inserisci(){ libro buflib; /*1*/ FILE *fp; /*2*/ fp=fopen("LibriSeq.dat","a"); /*3*/ if(fp==NULL) /*4*/ return; printf("\nInserimento di un libro"); printf("\nTitolo : "); gets(buflib.titolo); printf("Autore : "); gets(buflib.autore); printf("Editore : "); gets(buflib.editore); printf("Prezzo : "); scanf("%f",&buflib.prezzo); /* conservazione nel file */ fputs(buflib.titolo,fp); /*5*/ fprintf(fp,"\n"); fputs(buflib.autore,fp); fprintf(fp,"\n"); fputs(buflib.editore,fp); fprintf(fp,"\n"); fprintf(fp,"%4.2f\n",buflib.prezzo); fclose(fp); /*6*/ } /* Scansione sequenziale del file dei libri */ void esamina(){ libro buflib; FILE *fp; fp=fopen("LibriSeq.dat","r"); /*7*/ if(fp==NULL) return; for(;;){ if (fgets(buflib.titolo,50,fp)==NULL) /*8*/ break; fgets(buflib.autore,20,fp); /*9*/ fgets(buflib.editore,20,fp); fscanf(fp,"%f",&buflib.prezzo); fgetc(fp); /*10*/ puts(buflib.titolo); puts(buflib.autore); puts(buflib.editore); printf("%4.2f",buflib.prezzo); while(!getchar()=='\n'); } fclose(fp); }
Nella 1 viene definito il buffer che conterrà il libro da registrare nel file.
Nella riga 2 viene dichiarato un puntatore (file pointer) alla struttura FILE. Tale struttura, definita in stdio.h, in accordo con quanto espresso prima, rappresenterà il canale associato al file nel quale saranno conservati i dati sui libri.
Nella 3 viene effettuata una chiamata alla funzione fopen. Tale chiamata ritorna un puntatore al tipo FILE. I parametri da passare alla funzione richiedono di specificare una stringa contenente il nome con il quale il file è registrato nella memoria di massa e una stringa specificante la modalità di apertura del file. In questo caso il file è aperto in modalità append: i record saranno registrati di seguito a quelli già presenti nel file. Se il file non esiste verrà creato.
Il puntatore ritornato dalla fopen può essere NULL se il sistema non ha potuto generare, per un motivo qualsiasi, il file richiesto (per esempio se il dischetto è protetto da scrittura o se non c’è più spazio). Tale eventualità è testata nella 4.
A cominciare da 5 per scrivere i dati sul file, così come messo in evidenza prima, vengono utilizzate le funzioni fputs e fprintf formalmente uguali alle puts e printf più volte utilizzate. La funzione fputs, a differenza della puts, richiede di specificare oltre alla stringa da scrivere, la specifica del canale attraverso il quale effettuare l’operazione. Una osservazione simile vale per la fprintf, solo che stavolta il canale va specificato come primo parametro. Ogni registrazione di un singolo dato è seguita dalla registrazione di un carattere newline al fine di un più semplice reperimento dei singoli dati in fase di lettura. Per maggiori chiarimenti si legga quanto osservato nella funzione di lettura dal file.
La funzione fclose della 6 si occupa di interrompere le comunicazioni con il file.
Per poter accedere ai dati contenuti nel file, è necessario aprirlo in modalità read. Questo è ciò di cui si occupa l’istruzione contenuta nella riga 7.
La funzione esamina legge tutti i record registrati nel file e li visualizza sul video. A tal fine usa, come specificato in 8 e 9 le funzioni fgets e fscanf. La funzione fgets necessita, oltre che della specifica della stringa dove depositare la riga letta, della quantità massima di caratteri da leggere e del canale attraverso il quale effettuare la lettura. È opportuno notare che la funzione legge dal file fino al numero di caratteri specificato o al newline, se questo viene incontrato prima. Questo è il motivo dell’inserimento di tale carattere come delimitatore dei singoli dati: non si può infatti conoscere l’esatta lunghezza del dato contenuto nel campo e così si utilizza il newline come delimitatore. La funzione fgetc della 10 legge l’ultimo newline inserito dopo l’ultima fprintf in sede di scrittura.
L’elaborazione sequenziale di un file prevede la lettura di tutte le registrazioni contenute in esso così come sono state registrate. Per verificare l’avvenuta lettura di tutte le registrazioni contenute nel file, si è inserito il controllo specificato in 8. Se i libri registrati sono stati tutti letti, un ulteriore tentativo di lettura di una stringa ritorna un puntatore NULL.
http://ennebi.solira.org | ennebi@solira.org |