2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario Introduzione La gerarchia dei dati I file e gli stream Creare un file ad accesso sequenziale Leggere i dati da un file ad accesso sequenziale Modificare i dati in un file ad accesso sequenziale File ad accesso casuale Creare un file ad accesso casuale Scrivere i dati in modo casuale in un file ad accesso casuale Leggere i dati in modo casuale da un file ad accesso casuale Studio di un caso: un programma per elaborare delle transazioni
2000 Prentice Hall, Inc. All rights reserved Introduzione La memorizzazione dei dati nelle variabili e nei vettori è temporanea, decade con luscita dal programma Per memorizzare e conservare in modo permanente grandi quantità di dati si devono usare i file I calcolatori memorizzano i file su dispositivi di memoria di massa o secondaria (es. hard disk) I file di dati possono esser creati, elaborati e modificati dai programmi C
2000 Prentice Hall, Inc. All rights reserved La gerarchia dei dati (1/2) Bit – la più piccola unità di informazione –Può valere/memorizzare solo 0 oppure 1 Byte – aggregazione di 8 bit –Viene usato per memorizzare un carattere, che rappresenta una cifra decimale, una lettera o un simbolo ASCII Field – gruppo di caratteri (byte) avente significato proprio –Ad esempio il nome di una persona Record – gruppo di diversi field correlati –In C viene rappresentato attraverso una struct –Ad esempio, in un sistema di gestione dei pagamenti, un record di un impiegato può contenere i field ID, nome, indirizzo, salario, ecc... File – insieme di molteplici record correlati –Tutti i record del file sono correlati in quanto condividono gli stessi field –Ad esempio un file per la gestione dei pagamenti, che contiene i record di una serie di impiegati Database – gruppo di diversi file correlati
2000 Prentice Hall, Inc. All rights reserved La gerarchia dei dati (2/2) Chiave del record –Uno dei suoi campi è scelto come chiave in modo da identificare il record e facilitare il recupero di record specifici dal file –Nei file sequenziali i record sono tipicamente ordinati in base al valore chiave Judy Green SallyBlack TomBlue JudyGreen IrisOrange RandyRed File Record Field Byte (carattere ASCII: J) Bit
2000 Prentice Hall, Inc. All rights reserved. Il C vede i file come una sequenza di byte –Ogni file termina con un marcatore end-of-file –Oppure il file termina ad un determinato byte specificato Stream –E uninterfaccia logica di I/O che consente ad un programma C di leggere (o scrivere) dati da qualsiasi periferica (tastiera, video, file, stampante,..) –Il C definisce alcuni stream predefiniti (lettura da tastiera, scrittura a video) Gli stream stdin, stdout, stderr sono aperti automaticamente per ogni programma –Le loro funzionalità sono indipendenti dalla periferica a cui sono collegati Ad esempio, è possibile scrivere/leggere un file con la stessa sintassi con cui si scrive/legge sul monitor I File e gli Stream (1/4)
2000 Prentice Hall, Inc. All rights reserved I File e gli Stream (2/4) Quando un file viene aperto, gli viene associato uno stream –Uno stream fornisce un canale/flusso di comunicazione tra file e programmi –Lapertura di un file restituisce un puntatore ad una struttura di tipo FILE in questo caso la struttura è definita in, non dal programmatore –Esempi di puntatori a file: stdin - punta allo standard input (tastiera), visto come un file qualsiasi stdout - punta allo standard output (schermo), visto come un file qualsiasi stderr - punta allo standard error (schermo), visto come un file qualsiasi Ogni struttura di tipo FILE contiene, tra le altre cose, un File Descriptor (descrittore di file) –E un intero che rappresenta un indice allinterno di un vettore del Sistema Operativo, chiamato Tabella dei file aperti –Ogni elemento di questa tabella è un File Control Block (FCB), ovvero il blocco di controllo relativo ad un certo file –Un FCB contiene dei dati usati dal S.O. per amministrare il rispettivo file ogni volta che si incontra una istruzione C che agisce sul file stesso Gli FCB risiedono su disco, ma vengono caricati in RAM allapertura del file –Lelemento del vettore la cui posizione è data dal file descriptor contiene proprio il FCB relativo al file in esame
2000 Prentice Hall, Inc. All rights reserved I File e gli Stream (3/4)
2000 Prentice Hall, Inc. All rights reserved I File e gli Stream (4/4) Funzioni di lettura/scrittura di file nella libreria standard –int fgetc (FILE *fp) Legge un singolo carattere da un file e lo restituisce come intero Riceve come argomento un puntatore a FILE (il file da cui leggere) Usando fgetc(stdin) si legge il carattere da tastiera in modo del tutto equivalente alla funzione getchar() –int fputc (int c, FILE *fp) Scrive un singolo carattere in un file, passato come intero Riceve per argomento un puntatore a FILE e il carattere da scrivere sul file fputc('a',stdout) scrive a video un carattere, come putchar('a') –char * fgets (char *s, int n, FILE *fp) Legge (fino a n-1 caratteri) una riga dal file e la salva nella stringa (s) restituita –int fputs (const char *s, FILE *fp) Scrive una stringa (s) sul file, privata del terminatore \0 –int fscanf( FILE *fp,.. )/int fprintf( FILE *fp,.. ) Funzioni per lettura/scrittura formattata di file equivalenti a scanf e printf
2000 Prentice Hall, Inc. All rights reserved. Il C non impone una determinata struttura ai file –Nei file non esiste la nozione intrinseca di record, ovvero i file fisicamente possono contenere qualsiasi sequenza di byte di dati –E il programmatore che deve definire la struttura dei dati da memorizzare nei file per dar loro un significato e leggerli/scriverli in modo coerente Creazione di file ad accesso sequenziale FILE *filePtr; filePtr = fopen("mioFile.dat","w"); –Crea un puntatore a FILE da usare durante lelaborazione del file per riferirsi al file –Apre il file specificato, eventualmente creandolo, tramite fopen, che gli assegna il puntatore di riferimento e lo ritorna al chiamante fopen riceve due argomenti: un nome e il modo in cui va aperto il file (r/w/..) Se lapertura fallisce e quindi il file non viene aperto, ritorna NULL –Un programma può elaborare uno, nessuno o molti file –Ogni file deve avere un nome unico e un suo proprio puntatore specifico –Tutte le funzioni che elaboreranno il file aperto vi faranno riferimento tramite il puntatore opportuno Creare un file ad accesso sequenziale (1/3)
2000 Prentice Hall, Inc. All rights reserved. Altre funzioni per interagire con i file –fclose(FILE filePtr), chiude il file specificato dal puntatore Viene comunque eseguita automaticamente quando termina il programma E però buona pratica chiudere i file esplicitamente con questa istruzione –fprintf(FILE filePtr,..) analoga a printf, eccetto che riceve come primo argomento il puntatore al file su cui i dati vanno scritti –feof(FILE filePtr ), ritorna un valore diverso da zero (TRUE) solo se si è raggiunta la fine del file puntato Ovvero se si è arrivati al suo marcatore end-of-file, altrimenti ritorna zero Per linput da tastiera (file con puntatore stdin), feof verifica se si è finito di immettere dati e per impostare EOF lutente deve premere CTRL-Z Apre un file già esistente in sola lettura. Se il file non esiste, lapertura fallisce Apre o crea un file in sola scrittura. Se esiste già, ne elimina il contenuto attuale e vi scrive dallinizio Crea un file in sola scrittura. Se il file esiste già, vi scrive in accodamento, ovvero dalla fine del file Apre un file in lettura e scrittura. Se il file non esiste, lapertura fallisce Crea un file in lettura e scrittura. Se il file esiste già, ne elimina il contenuto attuale e vi scrive dallinizio Apre o crea un file in lettura e scrittura. Se esiste già, vi scrive in accodamento, ovvero dalla fine del file DescrizioneModo r w a r+ w+ a Creare un file ad accesso sequenziale (2/3)
2000 Prentice Hall, Inc. All rights reserved Creare un file ad accesso sequenziale (3/3) 1/* Fig. 11.3: fig11_03.c - Creare un file sequenziale */ 2#include 3 { 4int main(){ 6 int numConto; char nome[ 30 ]; float importo; 7 FILE *cfPtr; /* cfPtr => clienti.dat, puntatore a file */ 8 9 if ( ( cfPtr = fopen( "clienti.dat", "w" ) ) == NULL ) 10 printf( Impossibile creare il file\n" ); 11 else { 12 printf( Inserire numero conto, cliente e importo." ); 13 printf( Alla fine premere CTRL-Z.\n" ); 14 scanf( "%d%s%f", &numConto, nome, &importo ); 15 while ( !feof( stdin ) ){ 16 fprintf( cfPtr, "%d %s %.2f\n ", numConto, nome, importo ); 17 printf("? "); scanf("%d%s%f", &numConto, nome, &importo); 18 } 19 fclose( cfPtr ); 20 } 21 return 0; 22} Inserire numero conto, cliente e importo. Alla fine premere CRTL-Z. ? 200 Mezzalira ? 400 Giavardi ? ^Z 1. Inizializza variabili e puntatore a file 2. Collega il puntatore al file clienti.dat 3. Acquisisce i dati da tastiera 4. Scrive i dati sul file in modo formattato per poter distinguere poi i campi dati (va a capo per ogni record) Se utente scrive righe + lunghe di altre si salvano cosi su file 5. Chiude il file aperto Visualizzazione del programma (i dati poi sono scritti così sul file)
2000 Prentice Hall, Inc. All rights reserved Leggere i dati da un file ad accesso sequenziale (1/5) Lettura di un file ad accesso sequenziale –Per prima cosa va creato un puntatore a FILE e associato al file da leggere cfPtr = fopen(clienti.dat","r"); –Ora si può usare fscanf per leggere i dati da tale file fscanf(cfPtr, "%d%s%f, &numConto, nome, &importo); Analoga a scanf, eccetto che il primo argomento è un puntatore a FILE Usare formati senza %.2d o %7s ma generici fa leggere record di varie lunghezze File Position Pointer (puntatore di posizione nel file) –Indica il numero di posizione del prossimo byte da leggere/scrivere nel file –Non è realmente un puntatore, ma un valore intero, chiamato anche byte offset –I dati sono sempre letti ordinatamente dallinizio alla fine del file e quindi esso incrementa man mano durante la lettura di byte successivi –rewind(cfPtr) permette in ogni momento di riposizionare il File Position Pointer allinizio del file puntato da cfPtr (al byte 0) –I parametri della fopen impostano il valore iniziale del File Position Pointer Normalmente (r/w/r+/w+) esso viene impostato al byte 0 del file In caso di accodamento (a/a+), è impostato dopo lultimo byte dei dati già esistenti
2000 Prentice Hall, Inc. All rights reserved Leggere i dati da un file ad accesso sequenziale (2/5) 1/* Fig. 11.3: fig11_03.c - Leggere un file sequenziale */ 2#include 3 { 4int main(){ 6 int numConto; char nome[ 30 ]; float importo; 7 FILE *cfPtr; /* cfPtr => clienti.dat, puntatore a file */ 8 9 if ( ( cfPtr = fopen( "clienti.dat", r" ) ) == NULL ) 10 printf( "Impossibile aprire il file\n" ); 11 else{ 12 printf( "%-10s%-13s%s\n", Conto", Cliente", Importo" ); 13 fscanf( cfPtr, "%d%s%f", &numConto, nome, &importo ); 14 while ( !feof( cfPtr ) ){ 15 printf( "%-10d%-13s%7.2f\n", numConto, nome, importo ); 16 fscanf( cfPtr, "%d%s%lf", &numConto, nome, &importo ); 17 } 18 fclose( cfPtr ); 19 } 20 return 0; 21} 1. Inizializza variabili e puntatore a file 2. Collega il puntatore al file clienti.dat 3. Legge i dati dal file secondo un formato coerente al modo in cui sono stati scritti (intero, stringa, float) 4. Visualizza il record appena letto e legge il successivo 3. Chiude il file aperto Visualizzazione del programma Conto Cliente Importo 200 Mezzalira Giavardi
2000 Prentice Hall, Inc. All rights reserved Leggere i dati da un file ad accesso sequenziale (3/5) 1/* Fig. 11.8: fig11_08.c - Programma di stampa i dati dei clienti */ 2#include 3 4int main(){ 5 int scelta, numConto; 6 float importo; 7 char nome[30]; 8 FILE *cfPtr; 9 10 if( (cfPtr = fopen("clienti.dat","r")) == NULL ) 11 printf( "Impossibile aprire il file\n" ); 12 else{ 13 printf( Inserire loperazione da svolgere\n" 14 " 1-Stampa i conti con importo nullo" 15 " 2-Stampa i conti con credito\n" 16 " 3-Stampa i conti con debito" 17 " 4-Esci\n" ); 18 scanf("%d", &scelta); 19 while (scelta != 4){ 20 fscanf(cfPtr, "%d%s%f", &numConto, nome, &importo); 21 switch (scelta){ 22 case 1: 23 printf("\nConti con importo nullo:\n"); 1. Inizializza le variabili 2. Apre il file clienti.dat 3. Visualizza il menu delle scelte utente 4. Legge la prima riga (record) del file
2000 Prentice Hall, Inc. All rights reserved Leggere i dati da un file ad accesso sequenziale (4/5) 4.1. Finchè non arriva a fine file, stampa il record corrente solo se ha un importo nullo 4.2. Finchè non arriva a fine file, stampa il record corrente solo se ha un importo negativo 4.3. Finchè non arriva a fine file, stampa il record corrente solo se ha un importo positivo 25 if (importo == 0) 26 printf("%-10d%-13s%7.2f\n",numConto, nome, importo); 27 fscanf(cfPtr, "%d%s%lf", &numConto, nome, &importo); 28 } 29 break; 30 case 2: 31 printf("\nConti con credito:\n"); 32 while (!feof(cfPtr)){ 33 if (importo > 0) 34 printf("%-10d%-13s%7.2f\n",numConto, nome, importo); 35 fscanf(cfPtr, "%d%s%lf", &numConto, nome, &importo); 36 } 37 break; 38 case 3: 39 printf("\nConti con debito:\n"); 40 while (!feof(cfPtr)){ 41 if (importo < 0) 42 printf("%-10d%-13s%7.2f\n", numConto, nome,importo); 24 while (!feof(cfPtr)){ 43 fscanf(cfPtr, "%d%s%lf", &numConto, nome, &importo); 69 } 70 break; 71 }
2000 Prentice Hall, Inc. All rights reserved Leggere i dati da un file ad accesso sequenziale (5/5) Inserire loperazione da svolgere 1-Stampa i conti con importo nullo 2-Stampa i conti con credito 3-Stampa i conti con debito 4-Esci ? 1 Conti con importo nullo: 300 Bianchi 0.00 ? 2 Conti con credito: 400 Mezzalira ? 3 Conti con debito: 100 Rossi Giavardi ? 4 Fine esecuzione. Visualizzazione del programma 72 rewind(cfPtr); 73 printf("\n Prossima operazione?"); 74 scanf("%d", &scelta); 75 } 76 printf(Fine esecuzione.\n"); 77 fclose(cfPtr); 78 } 79 return 0; 80} 5. Riporta il puntatore di lettura del file a inizio file in caso di eventuali ripetizioni del programma ed acquisisce la nuova scelta dellutente 6. Infine chiude il file
2000 Prentice Hall, Inc. All rights reserved Modificare i dati in un file ad accesso sequenziale (1/2) Un File ad accesso sequenziale non può essere modificato senza correre il rischio di distruggere altri dati del file –E come modificare un file di testo con un editor senza abilitare linsert (sovrascrive i dati senza criterio) –Non si ha questo errore solo qualora i valori aggiornati abbiano la stessa dimensione degli originali nella stampa/scrittura formattata –E se si volesse aggiungere un nuovo record o eliminarne uno esistente? Esempio: 300 White Jones (vecchi dati) Se dovessimo cambiare il nome White in Worthington… 300 White Jones Worthington 0.00ones Worthington 0.00 I dati vengono sporcati in quanto parzialmente sovrascritti
2000 Prentice Hall, Inc. All rights reserved Modificare i dati in un file ad accesso sequenziale (2/2) Questo accade perché nella formattazione di input/output con fprintf e fscanf i campi possono cambiare dimensione –La rappresentazione dei dati nei file sequenziali e sullo schermo è differente rispetto alla loro rappresentazione interna (byte) –Esempio: 1, 34, -890 sono tutti numeri interi ma hanno dimensioni diverse se salvati su disco con file sequenziali Come int sono immagazzinati in memoria con lo stesso numero di byte Con la fprintf sono invece salvati su disco come campi aventi dimensioni differenti, date dal formato di stampa specificato Per aggiornare un record non si dovrebbe usare laccesso sequenziale con fprintf e fscanf –Se lo si volesse usare comunque, per evitare questi errori, si deve riscrive lintero file da capo (aprendolo in modalità w+, non con r+) –Oppure si memorizza ogni record su una riga (\n a fine fprintf) e quando si fa laggiornamento si modifica il record/riga intero –Nel primo modo si aggiornano correttamente anche i record successivi, mentre col secondo permane il problema di aggiungere/eliminare i record –I file sequenziali non sono indicati come database, vanno invece molto bene per creare report testuali, che si scrivono in un colpo solo
2000 Prentice Hall, Inc. All rights reserved File ad accesso casuale Nei file ad accesso casuale –Si accede ai record senza passare attraverso i record precedenti Laccesso ad ogni record richiede lo stesso tempo ed è istantaneo –I dati possono essere aggiornati senza distruggere altri dati I dati memorizzati in una posizione prefissata possono essere aggiornati o cancellati ed inoltre nuovi dati possono essere inseriti senza problemi Non è quindi necessario riscrivere lintero file Implementano record di lunghezza fissa –Mentre i file sequenziali contengono record di lunghezza variabile
2000 Prentice Hall, Inc. All rights reserved Creare un file ad accesso casuale (1/3) I dati nel file sono non formattati –Memorizzati come "raw bytes, conta solo il tipo del dato in ogni campo –Tutti i dati dello stesso tipo (es. int) usano la stessa quantità di memoria –Quindi tutti i record dello stesso tipo hanno lunghezza uguale e prefissata Funzioni I/O non formattate –E possibile accedere in lettura o scrittura ai dati di un file leggendo o scrivendo un intero blocco di dati (implementato con le struct) –fwrite, trasferisce N byte da una locazione di memoria ad un file fwrite(&numero,sizeof(int),1,mioPtr); &numero indica la locazione di memoria da cui trasferire il dato sizeof(int) indica il numero di byte da trasferire per ogni elemento 1 è il numero di elementi da trasferire e vale 1 se lorigine non è un vettore Per scrivere più elementi di un vettore, si passa il puntatore al vettore come primo argomento e come terzo il numero di elementi da scrivere mioPtr è il puntatore al file su cui trasferire i dati –fread, trasferisce N byte da un file ad una locazione di memoria fread(&numero,sizeof(int),1,mioPtr); &numero indica la locazione di memoria in cui trasferire il dato
2000 Prentice Hall, Inc. All rights reserved Creare un file ad accesso casuale (3/3) 1/* Fig : fig11_11.c 2 Creare in modo sequenziale un file ad accesso casuale */ 3#include 4 5struct datiCliente{ 6 int acctNum; 7 char cognome[15]; char nome[10]; 8 float importo; 9}; 10 11int main(){ 12 int i; 13 struct datiCliente tempCliente = { 0, "", "", 0.0 }; 14 FILE *cfPtr; if(( cfPtr = fopen("conti.dat","w")) == NULL) 17 printf(Impossibile creare il file.\n"); 18 else{ 19 for(i = 1;i <= 100;i++) 20 fwrite(&tempCliente, sizeof(struct datiCliente),1, cfPtr); 21 fclose( cfPtr ); 22 } 23 return 0; 24} 1. Definisce la struttura 2. Inizializza la variabile strutturata 3. Apre il file in scrittura 4. Scrive i campi della variabile strutturata sul file (scrittura non formattata) 5. Chiude il file
2000 Prentice Hall, Inc. All rights reserved Scrivere dati in modo casuale in un file ad accesso casuale (1/3) fseek –Scrivere i dati in modo casuale significa da una specifica posizione del file –Si usa la funzione fseek per impostare il puntatore di posizione del file nella posizione scelta e poi si usa la solita fwrite per scrivere i dati –La posizione da cui partire a scrivere è calcolata aggiungendo un certo numero di byte (offset) alla posizione data da una costante simbolica fseek(mioPtr,offset,base_const); mioPtr è il puntatore al file su cui scrivere offset è il valore da aggiungere alla costante simbolica base_const indica il punto da cui partire per aggiungere loffset –I valori che la costante simbolica può assumere sono: SEEK_SET – si somma loffset a partire dallinizio del file SEEK_CUR – si somma loffset a partire dalla posizione corrente nel file SEEK_END – si somma loffset a partire dalla fine del file
2000 Prentice Hall, Inc. All rights reserved Scrivere dati in modo casuale in un file ad accesso casuale (2/3) 1/* Fig : fig11_12.c - Scrive su un file ad accesso casuale */ 2#include 3 4struct datiCliente{ 6 int numConto; 7 char cognome[15]; char nome[10]; 9 float importo; 10}; 11 12int main(){ 13 FILE *cfPtr; 14 struct datiCliente tempCliente = { 0, "", "", 0.0 }; if ((cfPtr = fopen("conti.dat","r+")) == NULL) 17 printf( Impossibile aprire il file.\n" ); 18 else{ 19 printf(Inserire numero di conto (1-100,0 per finire)\n? "); 20 scanf("%d",&tempCliente.numConto); 21 while (tempCliente.numConto != 0){ 22 printf(Inserire cognome, nome, importo\n? "); 23 fscanf(stdin,"%s%s%f",tempCliente.cognome, 24 tempCliente.nome,&tempCliente.importo); 1. Definisce la struttura che rappresenta un blocco di dati (record) 2. Inizializza le variabili 3. Apre il file 4. Legge i dati in input finchè non riceve 0 per numero di conto 5. Scrive sul file i record dati dai campi della struttura client
2000 Prentice Hall, Inc. All rights reserved Scrivere dati in modo casuale in un file ad accesso casuale (3/3) 29 scanf("%d",&tempCliente.numConto); 30 } 31 fclose(cfPtr); 32 } 33 return 0; 34} 25 fseek(cfPtr,(tempCliente.numConto - 1) * 26 sizeof(struct datiCliente),SEEK_SET); 27 fwrite(&tempCliente, sizeof(struct datiCliente),1, cfPtr); 28 printf(Inserire numero di conto\n? "); 6. Scrive sul file i blocchi di dati ordinati per numero di conto (la posizione in cui mettere ognuno è data dalla fseek con offset dato dal numero di conto) 7. Chiude il file Inserire numero di conto (1-100, 0 per finire) ? 37 Inserire cognome, nome, importo ? Barker Doug 0.00 Inserire numero di conto ? 29 Inserire cognome, nome, importo ? Brown Nancy Inserire numero di conto ? 96 Inserire cognome, nome, importo ? Stone Sam Inserire numero di conto ? 0 Visualizzazione del programma
2000 Prentice Hall, Inc. All rights reserved Leggere dati in modo casuale da un file ad accesso casuale (1/2) 1/* Fig : fig11_15.c 2 Leggere in modo sequenziale un file ad accesso casuale */ 3#include 4 5struct datiCliente{ 6 int numConto; 7 char cognome[15]; char nome[10]; 8 float importo; 9}; 10 12int main(){ 13 FILE *cfPtr; 14 struct datiCliente tempCliente = { 0, "", "", 0.0 }; if((cfPtr = fopen("conti.dat","r")) == NULL) 17 printf(Impossibile aprire il file.\n"); 18 else{ 19 printf("%-6s%-16s%-11s%10s\n",Conto",Cognome", 20 Nome",Importo"); 21 while(!feof(cfPtr)){ 22 fread(&tempCliente, sizeof(struct datiCliente),1, cfPtr); 1. Definisce la struttura 2. Inizializza le variabili 3. Apre il file 4. Legge (con fread ) i blocchi di dati che ne costituiscono i record
2000 Prentice Hall, Inc. All rights reserved Leggere dati in modo casuale da un file ad accesso casuale (2/2) Conto Cognome Nome Importo 29 Brown Nancy Dunn Stacey Barker Doug Smith Dave Stone Sam Stampa a video i valori dei campi dei record 6. Chiude il file Visualizzazione del programma 33 fclose(cfPtr); 34 } 35 return 0; 36} 23 if(tempCliente.numConto != 0) 24 printf("%-6d%-16s%-11s%10.2f\n",tempCliente.numConto, 25 tempCliente.cognome,tempCliente.nome,tempCliente.importo); 26 }
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (1/8) Il programma usa dei file ad acceso casuale per gestire le informazioni relative ai costi di una banca Il programma: –Aggiornerà i costi esistenti –Aggiungerà quelli nuovi –Cancellerà i costi –Li archivierà in un file di testo
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (2/8) 1/* Fig : fig11_16.c – Mix accesso sequenziale e casuale */ 2#include 3 4struct datiCliente{ 6 int numConto; 7 char cognome[15]; char nome[10]; 9 float importo; 10}; 11 12int inserisciScelta(void); 13int scriviFileStampa(FILE *); 14int aggiornaConto(FILE *); 15int creaConto(FILE *); 16int cancellaConto(FILE *); 17 18int main(){ 19 FILE *cfPtr; 20 int scelta; if((cfPtr = fopen(conti.dat","r+")) == NULL) 23 printf(Impossibile aprire il file.\n"); 24 else{ 1. Definisce la struttura che rappresenta un blocco di dati (record) dei due file 2. Prototipi funzioni 3. Apre il file ad accesso diretto di riferimento conti.dat con i dati dei conti (quello poi passato alle funzioni)
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (3/8) 25 while( (scelta = inserisciScelta()) != 5 ){ 26switch( scelta ) { 27 case 1: 28 scriviFileStampa( cfPtr ); 29 break; 30 case 2: 31 aggiornaConto( cfPtr ); 32 break; 33 case 3: 34 creaConto( cfPtr ); 35 break; 36 case 4: 37 cancellaConto( cfPtr ); 38 break; 39} 40 } 41 fclose( cfPtr ); 42 } 43 return 0; 44} Acquisisce la scelta delloperazione da eseguire 5. Chiude il file dei conti che è stato aperto
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (4/8) 47void scriviFileStampa( FILE *leggiPtr ){ 48 FILE *scriviPtr; 49 struct datiCliente cliente = { 0, "", "", 0.0 }; if( ( scriviPtr = fopen( stampaconti.txt", "w" ) ) == NULL) 52 printf(Impossibile creare il file.\n"); 53 else{ 54 rewind( leggiPtr ); 55 fprintf( scriviPtr, "%-6s%-16s%-11s%10s\n", 56 " Conto", " Cognome", " Nome", " Importo" ); 57 while(!feof( leggiPtr )){ 58fread(&cliente, sizeof( struct datiCliente ), 1, leggiPtr); 59if(cliente.numConto != 0) 60 fprintf(scriviPtr,"%-6d%-16s%-11s%10.2f\n", 61 cliente.numConto, cliente.cognome, 62 cliente.nome, cliente.importo ); 63 } 64 fclose( scriviPtr ); 65 } 66} Definizione della funzione che scrive il file sequenziale formattato pronto per la stampa contenente dati dei conti presi da conti.dat 7. Apre il file in scrittura, riavvolge il file dato che è sequenziale, scrive in modo formattato lintestazione e in sequenza i dati dei conti dei clienti dal file di riferimento conti.dat
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (5/8) 69void aggiornaConto( FILE *fPtr ){ 70 int conto; float variazione; 71 struct datiCliente cliente = { 0, "", "", 0.0 }; printf( Inserire il numero di conto da modificare( ): "); 74 scanf( "%d", &conto ); 75 fseek( fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET ); 76 fread( &cliente, sizeof( struct datiCliente ), 1, fPtr ); 77 if( cliente.numConto == 0 ) 78 printf( Il conto #%d non esiste.\n", conto ); 79 else{ 80 printf( "%-6d%-16s%-11s%10.2f\n\n", cliente.numConto, 81 cliente.lastName, cliente.nome, cliente.importo ); 82 printf( Inserire accredito ( + ) o pagamento ( - ): " ); 83 scanf( "%lf", &variazione ); 84 cliente.importo += variazione; 85 printf( "%-6d%-16s%-11s%10.2f\n", cliente.numConto, 86 cliente.cognome, cliente.nome, cliente.importo ); 87 fseek(fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET); 88 fwrite( &cliente, sizeof( struct datiCliente ), 1, fPtr ); 89 } 90 } 8. Definizione della funzione che scrive il modifica un record di un conto e aggiorna limporto in base alla variazione inserita dallutente 9. Richiede il numero di conto da aggiornare, se esiste richiede la variazione di importo 10. Sposta il file pointer sul record indicato e applica la variazione
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (6/8) 91 void cancellaConto( FILE *fPtr ){ 92 int conto; 93 struct datiCliente cliente = { 0, "", "", 0.0 }; printf( Inserire il numero di conto da eliminare( ): "); 96 scanf( "%d", &conto ); 97 seek( fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET ); 98 fread( &cliente, sizeof( struct datiCliente ), 1, fPtr ); 99 if( cliente.numConto == 0 ) 100 printf( Il conto #%d non esiste.\n", conto ); 101 else{ 102 fseek(fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET); 103 fwrite( &cliente, sizeof( struct datiCliente ), 1, fPtr ); 104 } 105 } void creaConto( FILE *fPtr ){ 108 int conto; 109 struct datiCliente cliente = { 0, "", "", 0.0 }; printf( Inserire il numero del nuovo conto( ): "); 112 scanf( "%d", &conto ); 11. Definizione della funzione che elimina un record di un conto 12. Richiede il numero di conto da eliminare, se esiste sposta il file pointer sul record indicato e sovrascrive il record esistente con un record vuoto 13. Definizione della funzione che crea il record per un nuovo conto
2000 Prentice Hall, Inc. All rights reserved Caso di studio: programma per elaborare delle transazioni (7/8) 113 seek( fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET ); 114 fread( &cliente, sizeof( struct datiCliente ), 1, fPtr ); 115 if( cliente.numConto != 0 ) 116 printf( Il conto #%d esiste già.\n", conto ); 117 else{ 118 printf( Inserire cognome, nome, importo\n? " ); 119 scanf( "%s%s%lf", &cliente.cognome, &cliente.nome, 120 &cliente.importo ); 121 cliente.numConto = conto; 122 fseek(fPtr, (cliente.Numconto - 1) 123 * sizeof(struct datiCliente), SEEK_SET); 124 fwrite( &cliente, sizeof( struct datiCliente ), 1, fPtr ); 125 } 126 } int inserisciScelta( void ){ 129 int sceltaMenu; 130 printf( "\nInserire la scelta\n1) Scrivi il file di testo " 131 "formattato conti.txt\n2)Aggiorna conto\n3)Nuovo conto\n" 132 4)Cancella conto\n5)Esci\n? " ); 133 scanf( "%d", &sceltaMenu ); return sceltaMenu; 134 } 14. Richiede il numero del nuovo conto, se non esiste già richiede i dati del nuovo conto 15. Crea la struttura del record da inserire con i dati ricevuti, sposta il file pointer sulla posizione data dal nuovo numero di conto e scrive il record indicato 16. Definizione della funzione che riceve la scelta dellutente sullazione da svolgere
2000 Prentice Hall, Inc. All rights reserved. Visualizzazione del programma Caso di studio: programma per elaborare delle transazioni (8/8) Inserire il numero di conto da modificare(1-100): Barker Doug 0.00 Inserire accredito (+) o pagamento (-): Barker Doug Insrire il numero del nuovo conto(1-100): 22 Inserire cognome, nome, importo ? Johnston Sarah Conto Cognome Nome Importo 29 Brown Nancy Dunn Stacey Barker Doug Smith Dave Stone Sam 34.98