prof. Nunzio Brugaletta | Programmazione e linguaggio C |
Se il supporto sul quale sono registrati i dati è gestito da un dispositivo che lo consente, è possibile accedere ad una registrazione qualsiasi contenuta nel file, specificando la sua posizione relativa all’interno del file stesso. La logica di gestione di un file ad accesso casuale somiglia a quella conosciuta della gestione di una tabella. Anche in quel caso i record erano accessibili specificando la loro posizione relativa. Spingendo la similitudine con gli argomenti trattati in precedenza si può dire che i record in un file sequenziale sono elaborati come gli elementi di una coda, in un file ad accesso casuale come una tabella.
/* Gestione file di libri con elaborazione sequenziale ed accesso diretto */ #include <stdio.h> /* Definizione del record */ typedef struct { char titolo[50]; char autore[20]; char editore[20]; float prezzo; }libro; ... /* Inserimento di un libro nel file */ void inserisci(){ /*1*/ FILE *fp; libro buflib; fp=fopen("DatiLib.dat","a"); /*2*/ if(fp==NULL) return; printf("\nInserimento di un libro"); fflush(stdin); printf("\nTitolo : "); gets(buflib.titolo); printf("Autore : "); gets(buflib.autore); printf("Editore : "); gets(buflib.editore); printf("Prezzo :"); scanf("%f",&buflib.prezzo); fwrite(&buflib,sizeof(libro),1,fp); /*3*/ fclose(fp); } /* Estrazione di un libro dal file */ void estrai(){ /*4*/ FILE *fp; libro buflib; int quale; long dove; fp=fopen("DatiLib.dat","r"); /*5*/ if(fp==NULL) return; printf("\nEstrazione di un libro dal file"); printf("\nQuale libro :"); scanf("%d",&quale); /*6*/ dove=(long) sizeof(libro)*(quale-1); /*7*/ fseek(fp,dove,SEEK_SET); /*8*/ if(!fread(&buflib,sizeof(libro),1,fp)){ /*9*/ printf("\nLibro inesistente"); return; } puts(buflib.titolo); puts(buflib.autore); puts(buflib.editore); printf("%4.2f\n",buflib.prezzo); while(!getchar()=='\n'); fclose(fp); } /* Scansione sequenziale del file */ void esamina(){ /*10*/ FILE *fp; libro buflib; fp=fopen("DatiLib.dat","r"); if(fp==NULL) return; printf("\nLibri conservati nel file\n"); fread(&buflib,sizeof(libro),1,fp); /*11*/ while(!feof(fp)){ /*12*/ puts(buflib.titolo); puts(buflib.autore); puts(buflib.editore); printf("%4.2f\n",buflib.prezzo); while(!getchar()=='\n'); fread(&buflib,sizeof(libro),1,fp); /*11*/ } fclose(fp); } /* Modifica dati di un libro esistente */ void modifica(){ /*12*/ FILE *fp; libro buflib; int quale; long dove; fp=fopen("DatiLib.dat","r+"); /*13*/ if(fp==NULL) return; printf("\nModifica dati libro dal file"); /*14*/ printf("\nQuale libro :"); scanf("%d",&quale); while(!getchar()=='\n'); dove=(long) sizeof(libro)*(quale-1); fseek(fp,dove,SEEK_SET); if(!fread(&buflib,sizeof(libro),1,fp)){ printf("\nLibro inesistente"); return; } puts(buflib.titolo); puts(buflib.autore); puts(buflib.editore); printf("%4.2f\n",buflib.prezzo); /* Nuovi dati */ printf("\nNuovi dati libro"); /*15*/ fflush(stdin); printf("\nTitolo : "); gets(buflib.titolo); printf("Autore : "); gets(buflib.autore); printf("Editore : "); gets(buflib.editore); printf("Prezzo :"); scanf("%f",&buflib.prezzo); fseek(fp,dove,SEEK_SET); /*16*/ fwrite(&buflib,sizeof(libro),1,fp); /*17*/ fclose(fp); }
La funzione inserisci definita in 1 si occupa, allo stesso modo dell’equivalente nell’esempio del file sequenziale, della conservazione di un libro nel file. Formalmente è molto simile all’altra vista in precedenza. Anche in questo caso c’è un buffer per la conservazione temporanea del record da registrare e un puntatore alla struttura FILE. Anche l’apertura del file viene effettuata, come si legge in 2, per mezzo di una chiamata alla funzione fopen.
Per quanto riguarda la scrittura dei dati sul file, in questo caso, viene utilizzata nella 3 la funzione fwrite che si occupa di scrivere un blocco di byte. Tale funzione richiede come parametri un puntatore all’area da cui prelevare i dati da scrivere (&buflib), il numero di byte che devono essere scritti (sizeof(libro)), quanti blocchi di quella dimensione scrivere (1), il canale da utilizzare (fp).
La funzione estrai della 4, dopo aver aperto in 5 il file similmente alla equivalente nel file sequenziale, si occupa di rintracciare una specifica registrazione all’interno del file, una volta conosciuta la dimensione comune dei record conservati nel file e la posizione del record interessato. Il metodo utilizzato, per il rintracciamento del record interessato, è lo stesso di quello utilizzato per il rintracciamento di un elemento in una struttura sequenziale (indirizzo base, scostamento da effettuare): nella 6 viene richiesto di specificare la posizione del record da leggere, nella 7 tale posizione relativa viene trasformata in indirizzo relativo. Si noti che l’espressione qui utilizzata è l’equivalente della seconda parte di IND(xi)=INDb+(i-1)l, infatti qui la dimensione comune degli elementi è rappresentata da sizeof(libro). L’espressione per esteso è scritta nella 8, dove la funzione fseek permette di posizionarsi sul record interessato. La funzione richiede infatti come parametri oltre che il puntatore al file (fp) l’indirizzo base da cui partire (SEEK_SET è il simbolo utilizzato per indicare l’inizio del file ed è definito in stdio.h), lo scostamento relativo calcolato in precedenza. Si noti che è semplicemente un modo diverso di scrivere l’espressione ricordata prima.
Effettuato il posizionamento, la funzione fread della 9 si occupa di depositare nel buffer predisposto (l’area di memoria associata a &buflib) il record letto. La funzione richiede gli stessi parametri della fwrite utilizzata in 3. La funzione ritorna un puntatore all’area utilizzata per conservare il record letto (lo stesso valore di &buflib). Se l’operazione di lettura non ha avuto esito positivo, per esempio perché non esiste un record registrato all’indirizzo specificato, il puntatore assume valore NULL: tale condizione è testata appunto nella 9.
I record conservati in un file ad accesso casuale possono essere elaborati anche sequenzialmente ed è di questo tipo di elaborazione che si occupa la funzione esamina della 10. Anche in questo caso, dopo aver effettuato le solite operazioni, si procede alla lettura di tutti i record contenuti nel file nello stesso ordine in cui sono registrati: a tale fine è utilizzata la funzione fread delle 11. La prima volta del suo utilizzo, poiché non è stata utilizzata la fseek, viene letto il primo record registrato. Ogni nuova chiamata alla fread ritorna in buflib il record successivo e in questo modo possono essere letti tutte le registrazioni contenute nel file. Non conoscendo la quantità di record registrati nel file, è necessario utilizzare la funzione feof. Tale funzione ritorna il valore di verità (1) se nell’ultima operazione di lettura, dal canale specificato come parametro (fp nell’esempio), si è raggiunti la fine del file.
La funzione modifica che comincia da 12, si occupa dell'update dei dati di un libro già registrato precedentemente nel file. Per buona parte è formalmente simile alla estrai della 4: anche in questo caso si tratta di posizionarsi su uno specifico record del file e leggerlo, solo che stavolta se ne vuole registrare una nuova versione modificata. Nella 13 si apre in modalità update (identificata dal parametro r+ della open) il file interessato. Il gruppo di istruzioni che comincia da 14 è lo stesso di quello che si ritrova nella estrai: si cerca il libro interessato dalla modifica, lo si carica in memoria e si visualizza l'attuale contenuto dei campi. A cominciare dalla 15 si ricevono i nuovi dati da registrare. Nella 16 ci si riposiziona nel punto da cui si è letto il record. Si sono già fatte notare le analogie con la tabella: anche qui per effettuare operazioni su singoli elementi deve essere specificata la relativa posizione. La 17, identica alla 3, si occupa di scrivere il record nella posizione specificata in precedenza.
http://ennebi.solira.org | ennebi@solira.org |