2000 prentice hall, inc. all rights reserved. capitolo 11 (deitel) lelaborazione dei file sommario...

34
2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) L’elaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3 - I file e gli stream 11.4 - Creare un file ad accesso sequenziale 11.5 - Leggere i dati da un file ad accesso sequenziale 11.6 - Modificare i dati in un file ad accesso sequenziale 11.7 - File ad accesso casuale 11.8 - Creare un file ad accesso casuale 11.9 - Scrivere i dati in modo casuale in un file ad accesso casuale 11.10 - Leggere i dati in modo casuale da un file ad accesso casuale 11.11 - Studio di un caso: un programma per elaborare delle transazioni

Upload: piera-gigli

Post on 02-May-2015

216 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

Capitolo 11 (Deitel)L’elaborazione dei file

Sommario

11.1 - Introduzione11.2 - La gerarchia dei dati11.3 - I file e gli stream11.4 - Creare un file ad accesso sequenziale11.5 - Leggere i dati da un file ad accesso sequenziale11.6 - Modificare i dati in un file ad accesso sequenziale11.7 - File ad accesso casuale11.8 - Creare un file ad accesso casuale11.9 - Scrivere i dati in modo casuale in un file ad accesso casuale11.10 - Leggere i dati in modo casuale da un file ad accesso casuale 11.11 - Studio di un caso: un programma per elaborare delle transazioni

Page 2: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.1 - Introduzione

• La memorizzazione dei dati nelle variabili e nei vettori è temporanea, decade con l’uscita 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

Page 3: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.2 - 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

Page 4: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.2 - 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

1

01001010

Judy

Judy Green

Sally BlackTom BlueJudy GreenIris OrangeRandy Red

File

Record

Field

Byte (carattere ASCII: J)

Bit

Page 5: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

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’ un’interfaccia 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

11.3 - I File e gli Stream (1/4)

Page 6: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.3 - 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– L’apertura di un file restituisce un puntatore ad una struttura di tipo FILE

• in questo caso la struttura è definita in <stdio.h>, 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 all’interno 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 all’apertura del file

– L’elemento del vettore la cui posizione è data dal file descriptor contiene proprio il FCB relativo al file in esame

Page 7: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.3 - I File e gli Stream (3/4)

Page 8: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.3 - 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

Page 9: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

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 sequenzialeFILE *filePtr;filePtr = fopen("mioFile.dat","w");

– Crea un puntatore a FILE da usare durante l’elaborazione 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 l’apertura 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

11.4 - Creare un file ad accesso sequenziale (1/3)

Page 10: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.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 l’input da tastiera (“file” con puntatore stdin), feof verifica se si è finito di

immettere dati e per impostare EOF l’utente deve premere CTRL-Z

Apre un file già esistente in sola lettura. Se il file non esiste, l’apertura fallisce

Apre o crea un file in sola scrittura. Se esiste già, ne elimina il contenuto attuale e vi scrive dall’inizio

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, l’apertura fallisce

Crea un file in lettura e scrittura. Se il file esiste già, ne elimina il contenuto attuale e vi scrive dall’inizio

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+

11.4 - Creare un file ad accesso sequenziale (2/3)

Page 11: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.4 - Creare un file ad accesso sequenziale (3/3)

1 /* Fig. 11.3: fig11_03.c - Creare un file sequenziale */

2 #include <stdio.h>

3

4 int 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 345.67? 400 Giavardi -42.16? ^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 poisono scritti così sul file)

Page 12: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.5 - 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 dall’inizio 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 all’inizio 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 l’ultimo byte dei dati già esistenti

Page 13: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.5 - Leggere i dati da un file ad accesso sequenziale (2/5)

1 /* Fig. 11.3: fig11_03.c - Leggere un file sequenziale */

2 #include <stdio.h>

3

4 int 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 Importo200 Mezzalira 345.67400 Giavardi -42.16

Page 14: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.5 - 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 <stdio.h>34 int main(){

5 int scelta, numConto;6 float importo;7 char nome[30];8 FILE *cfPtr;910 if( (cfPtr = fopen("clienti.dat","r")) == NULL )11 printf( "Impossibile aprire il file\n" );12 else{ 13 printf( “Inserire l’operazione 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

Page 15: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.5 - 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 }

Page 16: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.5 - Leggere i dati da un file ad accesso sequenziale (5/5)

Inserire l’operazione da svolgere

1-Stampa i conti con importo nullo 2-Stampa i conti con credito3-Stampa i conti con debito 4-Esci? 1Conti con importo nullo:300 Bianchi 0.00? 2Conti con credito:400 Mezzalira -42.16? 3Conti con debito:100 Rossi 24.98200 Giavardi 345.67? 4Fine 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 dell’utente

6. Infine chiude il file

Page 17: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.6 - 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 l’insert (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 0.00 400 Jones 32.87 (vecchi dati)

Se dovessimo cambiare il nome White in Worthington…

300 White 0.00 400 Jones 32.87

300 Worthington 0.00ones 32.87

300 Worthington 0.00

I dati vengono sporcati in quanto parzialmente sovrascritti

Page 18: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.6 - Modificare i dati in un filead 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 l’accesso sequenziale con fprintf e fscanf – Se lo si volesse usare comunque, per evitare questi errori, si deve riscrive

l’intero 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 l’aggiornamento 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

Page 19: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.7 - File ad accesso casuale

• Nei file ad accesso casuale – Si accede ai record senza passare attraverso i record precedenti

• L’accesso 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 l’intero file

• Implementano record di lunghezza fissa– Mentre i file sequenziali contengono record di lunghezza variabile

0 200 300 400 500

byte offsets}

} } } } } }

100

100bytes

100bytes

100bytes

100bytes

100bytes

100bytes

Page 20: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.8 - 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 l’origine 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

Page 21: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.8 - Creare un file ad accesso casuale (3/3)

1 /* Fig. 11.11: fig11_11.c

2 Creare in modo sequenziale un file ad accesso casuale */

3 #include <stdio.h>

4

5 struct datiCliente{

6 int acctNum;

7 char cognome[15]; char nome[10];

8 float importo;

9 };

10

11 int main(){12 int i;

13 struct datiCliente tempCliente = { 0, "", "", 0.0 };

14 FILE *cfPtr;

15

16 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

Page 22: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.9 - 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 l’offset

– I valori che la costante simbolica può assumere sono:• SEEK_SET – si somma l’offset a partire dall’inizio del file• SEEK_CUR – si somma l’offset a partire dalla posizione corrente nel file• SEEK_END – si somma l’offset a partire dalla fine del file

Page 23: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.9 - Scrivere dati in modo casuale in

un file ad accesso casuale (2/3)1 /* Fig. 11.12: fig11_12.c - Scrive su un file ad accesso casuale */

2 #include <stdio.h>34 struct datiCliente{ 6 int numConto;7 char cognome[15]; char nome[10];9 float importo;10 };11 12 int main(){

13 FILE *cfPtr;14 struct datiCliente tempCliente = { 0, "", "", 0.0 };1516 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

Page 24: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.9 - 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 fileInserire numero di conto (1-100, 0 per finire)? 37Inserire cognome, nome, importo? Barker Doug 0.00Inserire numero di conto? 29Inserire cognome, nome, importo? Brown Nancy -24.54Inserire numero di conto? 96Inserire cognome, nome, importo? Stone Sam 34.98Inserire numero di conto? 0

Visualizzazionedel programma

Page 25: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.10 - Leggere dati in modo casuale da

un file ad accesso casuale (1/2)1 /* Fig. 11.15: fig11_15.c2 Leggere in modo sequenziale un file ad accesso casuale */3 #include <stdio.h>45 struct datiCliente{ 6 int numConto;7 char cognome[15]; char nome[10];

8 float importo;9 };1012 int main(){

13 FILE *cfPtr;14 struct datiCliente tempCliente = { 0, "", "", 0.0 };1516 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

Page 26: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.10 - Leggere dati in modo casuale da

un file ad accesso casuale (2/2)

Conto Cognome Nome Importo29 Brown Nancy -24.5433 Dunn Stacey 314.3337 Barker Doug 0.0088 Smith Dave 258.3496 Stone Sam 34.98

5. 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 }

Page 27: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - 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

Page 28: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - Caso di studio: programma per elaborare delle transazioni (2/8)

1 /* Fig. 11.16: fig11_16.c – Mix accesso sequenziale e casuale */

2 #include <stdio.h>34 struct datiCliente{ 6 int numConto;7 char cognome[15]; char nome[10];9 float importo;10 };11 12 int inserisciScelta(void);

13 int scriviFileStampa(FILE *); 14 int aggiornaConto(FILE *); 15 int creaConto(FILE *); 16 int cancellaConto(FILE *); 1718 int main(){ 19 FILE *cfPtr;20 int scelta;2122 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)

Page 29: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - Caso di studio: programma per elaborare delle transazioni (3/8)

25 while( (scelta = inserisciScelta()) != 5 ){

26 switch( 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 }4546

4. Acquisisce la scelta dell’operazione da eseguire

5. Chiude il file dei conti che è stato aperto

Page 30: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - Caso di studio: programma per elaborare delle transazioni (4/8)

47 void scriviFileStampa( FILE *leggiPtr ){

48 FILE *scriviPtr;49 struct datiCliente cliente = { 0, "", "", 0.0 };5051 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 )){ 58 fread(&cliente, sizeof( struct datiCliente ), 1, leggiPtr);59 if(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 }6768

6. 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 l’intestazione e in sequenza i dati dei conti dei clienti dal file di riferimento “conti.dat”

Page 31: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - Caso di studio: programma per elaborare delle transazioni (5/8)

69 void aggiornaConto( FILE *fPtr ){

70 int conto; float variazione;71 struct datiCliente cliente = { 0, "", "", 0.0 };7273 printf( “Inserire il numero di conto da modificare(1 - 100): ");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 l’importo in base alla variazione inserita dall’utente

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

Page 32: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - 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 };9495 printf( “Inserire il numero di conto da eliminare(1 - 100): ");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 }106107 void creaConto( FILE *fPtr ){108 int conto;109 struct datiCliente cliente = { 0, "", "", 0.0 };110111 printf( “Inserire il numero del nuovo conto(1 - 100): ");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

Page 33: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

11.11 - 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 }127128 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 dell’utente sull’azione da svolgere

Page 34: 2000 Prentice Hall, Inc. All rights reserved. Capitolo 11 (Deitel) Lelaborazione dei file Sommario 11.1 - Introduzione 11.2 - La gerarchia dei dati 11.3

2000 Prentice Hall, Inc. All rights reserved.

Visualizzazione del programma

11.11 - Caso di studio: programma per elaborare delle transazioni (8/8)

Inserire il numero di conto da modificare(1-100): 3737 Barker Doug 0.00 Inserire accredito (+) o pagamento (-): +87.9937 Barker Doug 87.99

Insrire il numero del nuovo conto(1-100): 22Inserire cognome, nome, importo? Johnston Sarah 247.45

<Dopo aver scelto l’opzione 1, il file conti.txt contiene>

Conto Cognome Nome Importo29 Brown Nancy -24.5433 Dunn Stacey 314.3337 Barker Doug 0.0088 Smith Dave 258.3496 Stone Sam 34.98