...

9.L`elaborazione dei file (Cap. 11 Deitel)

by user

on
Category: Documents
12

views

Report

Comments

Transcript

9.L`elaborazione dei file (Cap. 11 Deitel)
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
 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
 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
 2000 Prentice Hall, Inc. All rights reserved.
11.2 - La gerarchia dei dati (2/2)
Sally
Tom
Judy
Iris
Randy
Judy
Black
Blue
Green
Orange
Red
Green
Judy
File
Record
Field
01001010 Byte
(carattere ASCII: J)
1 Bit
• 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
 2000 Prentice Hall, Inc. All rights reserved.
11.3 - I File e gli Stream (1/4)
• 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
 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
 2000 Prentice Hall, Inc. All rights reserved.
11.3 - I File e gli Stream (3/4)
 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
 2000 Prentice Hall, Inc. All rights reserved.
11.4 - Creare un file ad accesso sequenziale (1/3)
• 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 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
 2000 Prentice Hall, Inc. All rights reserved.
11.4 - Creare un file ad accesso sequenziale (2/3)
Modo
Descrizione
r
Apre un file già esistente in sola lettura. Se il file non esiste, l’apertura fallisce
w
Apre o crea un file in sola scrittura. Se esiste già, ne elimina il contenuto attuale e vi scrive dall’inizio
a
Crea un file in sola scrittura. Se il file esiste già, vi scrive in accodamento, ovvero dalla fine del file
r+
Apre un file in lettura e scrittura. Se il file non esiste, l’apertura fallisce
w+
Crea un file in lettura e scrittura. Se il file esiste già, ne elimina il contenuto attuale e vi scrive dall’inizio
a+
Apre o crea un file in lettura e scrittura. Se esiste già, vi scrive in accodamento, ovvero dalla fine del file
• 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
 2000 Prentice Hall, Inc. All rights reserved.
11.4 - Creare un file ad accesso sequenziale (3/3)
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* Fig. 11.3: fig11_03.c - Creare un file sequenziale */
#include <stdio.h>
int main(){
int numConto; char nome[ 30 ]; float importo;
FILE *cfPtr;
/* cfPtr => clienti.dat, puntatore a file */
if ( ( cfPtr = fopen( "clienti.dat", "w" ) ) == NULL )
printf( “Impossibile creare il file\n" );
else {
printf( “Inserire numero conto, cliente e importo." );
printf( “Alla fine premere CTRL-Z.\n" );
scanf( "%d%s%f", &numConto, nome, &importo );
while ( !feof( stdin ) ){
fprintf( cfPtr, "%d %s %.2f\n ", numConto, nome, importo );
printf("? "); scanf("%d%s%f", &numConto, nome, &importo);
}
fclose( cfPtr );
}
return 0;
}
Inserire numero conto, cliente e importo. Alla fine premere CRTL-Z.
? 200 Mezzalira 345.67
? 400 Giavardi -42.16
? ^Z
 2000 Prentice Hall, Inc. All rights reserved.
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)
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
 2000 Prentice Hall, Inc. All rights reserved.
11.5 - Leggere i dati da un file
ad accesso sequenziale (2/5)
1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Fig. 11.3: fig11_03.c - Leggere un file sequenziale */
#include <stdio.h>
int main(){
int numConto; char nome[ 30 ]; float importo;
FILE *cfPtr;
/* cfPtr => clienti.dat, puntatore a file */
if ( ( cfPtr = fopen( "clienti.dat", “r" ) ) == NULL )
printf( "Impossibile aprire il file\n" );
else{
printf( "%-10s%-13s%s\n", “Conto", “Cliente", “Importo" );
fscanf( cfPtr, "%d%s%f", &numConto, nome, &importo );
while ( !feof( cfPtr ) ){
printf( "%-10d%-13s%7.2f\n", numConto, nome, importo );
fscanf( cfPtr, "%d%s%lf", &numConto, nome, &importo );
}
fclose( cfPtr );
}
return 0;
}
Conto
200
400
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
Cliente
Mezzalira
Giavardi
Importo
345.67
-42.16
 2000 Prentice Hall, Inc. All rights reserved.
Visualizzazione del
programma
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>
3
4 int 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 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");
 2000 Prentice Hall, Inc. All rights reserved.
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
11.5 - Leggere i dati da un file
ad accesso sequenziale (4/5)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
69
70
71
while (!feof(cfPtr)){
if (importo == 0)
printf("%-10d%-13s%7.2f\n",numConto, nome, importo);
fscanf(cfPtr, "%d%s%lf", &numConto, nome, &importo);
}
break;
case 2:
printf("\nConti con credito:\n");
while (!feof(cfPtr)){
if (importo > 0)
printf("%-10d%-13s%7.2f\n",numConto, nome, importo);
fscanf(cfPtr, "%d%s%lf", &numConto, nome, &importo);
}
break;
case 3:
printf("\nConti con debito:\n");
while (!feof(cfPtr)){
if (importo < 0)
printf("%-10d%-13s%7.2f\n", numConto, nome,importo);
fscanf(cfPtr, "%d%s%lf", &numConto, nome, &importo);
}
break;
}
 2000 Prentice Hall, Inc. All rights reserved.
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
11.5 - Leggere i dati da un file
ad accesso sequenziale (5/5)
72
73
74
75
76
77
78
79
80 }
rewind(cfPtr);
printf("\n Prossima operazione?");
scanf("%d", &scelta);
}
printf(“Fine esecuzione.\n");
fclose(cfPtr);
}
return 0;
6. Infine chiude il file
Inserire l’operazione da svolgere
1-Stampa i conti con importo nullo
3-Stampa i conti con debito
? 1
Conti con importo nullo:
300
Bianchi
0.00
? 2
Conti con credito:
400
Mezzalira
-42.16
? 3
Conti con debito:
100
Rossi
24.98
200
Giavardi
345.67
? 4
Fine esecuzione.
 2000 Prentice Hall, Inc. All rights reserved.
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
2-Stampa i conti con credito
4-Esci
Visualizzazione
del programma
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
Esempio:
300 White 0.00 400 Jones 32.87
(vecchi dati)
Se dovessimo cambiare il nome White in Worthington…
300 Worthington 0.00
300 White 0.00 400 Jones 32.87
300 Worthington 0.00ones 32.87
I dati vengono sporcati
in quanto parzialmente
sovrascritti
– 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?
 2000 Prentice Hall, Inc. All rights reserved.
11.6 - 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 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
 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
100
200
300
400
500
}
byte offsets
}
}
}
}
}
}
100
100
100
100
100
100
bytes
bytes
bytes
bytes
bytes
bytes
 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
 2000 Prentice Hall, Inc. All rights reserved.
11.8 - Creare un file ad accesso casuale (3/3)
1
2
3
4
/* Fig. 11.11: fig11_11.c
Creare in modo sequenziale un file ad accesso casuale */
#include <stdio.h>
5
6
7
struct datiCliente{
int acctNum;
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
17
18
19
20
21
22
23
24 }
if(( cfPtr = fopen("conti.dat","w")) == NULL)
printf(“Impossibile creare il file.\n");
else{
for(i = 1;i <= 100;i++)
fwrite(&tempCliente, sizeof(struct datiCliente),1, cfPtr);
fclose( cfPtr );
}
return 0;
 2000 Prentice Hall, Inc. All rights reserved.
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
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
 2000 Prentice Hall, Inc. All rights reserved.
11.9 - Scrivere dati in modo casuale in
un file ad accesso casuale (2/3)
1
2
3
4
6
7
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Fig. 11.12: fig11_12.c - Scrive su un file ad accesso casuale */
#include <stdio.h>
struct datiCliente{
int numConto;
char cognome[15]; char nome[10];
float importo;
};
1. Definisce la struttura
che rappresenta un
blocco di dati (record)
int main(){
FILE *cfPtr;
struct datiCliente tempCliente = { 0, "", "", 0.0 };
2. Inizializza le variabili
if ((cfPtr = fopen("conti.dat","r+")) == NULL)
printf( “Impossibile aprire il file.\n" );
else{
printf(“Inserire numero di conto (1-100,0 per finire)\n? ");
scanf("%d",&tempCliente.numConto);
while (tempCliente.numConto != 0){
printf(“Inserire cognome, nome, importo\n? ");
fscanf(stdin,"%s%s%f",tempCliente.cognome,
tempCliente.nome,&tempCliente.importo);
3. Apre il file
 2000 Prentice Hall, Inc. All rights reserved.
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
11.9 - Scrivere dati in modo casuale in
un file ad accesso casuale (3/3)
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? ");
29
scanf("%d",&tempCliente.numConto);
30
}
31
fclose(cfPtr);
32
}
33
return 0;
34 }
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 -24.54
Inserire numero di conto
? 96
Inserire cognome, nome, importo
? Stone Sam 34.98
Inserire numero di conto
? 0
 2000 Prentice Hall, Inc. All rights reserved.
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
Visualizzazione
del programma
11.10 - Leggere dati in modo casuale da
un file ad accesso casuale (1/2)
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17
18
19
20
21
22
/* Fig. 11.15: fig11_15.c
Leggere in modo sequenziale un file ad accesso casuale */
#include <stdio.h>
struct datiCliente{
int numConto;
char cognome[15]; char nome[10];
float importo;
};
int main(){
FILE *cfPtr;
struct datiCliente tempCliente = { 0, "", "", 0.0 };
1. Definisce la struttura
2. Inizializza le variabili
3. Apre il file
if((cfPtr = fopen("conti.dat","r")) == NULL)
printf(“Impossibile aprire il file.\n");
else{
printf("%-6s%-16s%-11s%10s\n",“Conto",“Cognome",
“Nome",“Importo");
while(!feof(cfPtr)){
fread(&tempCliente, sizeof(struct datiCliente),1, cfPtr);
 2000 Prentice Hall, Inc. All rights reserved.
4. Legge (con fread) i
blocchi di dati che ne
costituiscono i record
11.10 - Leggere dati in modo casuale da
un file ad accesso casuale (2/2)
23
24
25
26
33
34
35
36 }
Conto
29
33
37
88
96
if(tempCliente.numConto != 0)
printf("%-6d%-16s%-11s%10.2f\n",tempCliente.numConto,
tempCliente.cognome,tempCliente.nome,tempCliente.importo);
}
fclose(cfPtr);
6. Chiude il file
}
return 0;
Cognome
Brown
Dunn
Barker
Smith
Stone
Nome
Nancy
Stacey
Doug
Dave
Sam
 2000 Prentice Hall, Inc. All rights reserved.
5. Stampa a video i
valori dei campi
dei record
Importo
-24.54
314.33
0.00
258.34
34.98
Visualizzazione
del programma
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
 2000 Prentice Hall, Inc. All rights reserved.
11.11 - Caso di studio: programma per
elaborare delle transazioni (2/8)
1
2
3
4
6
7
9
10
11
12
/* Fig. 11.16: fig11_16.c – Mix accesso sequenziale e casuale */
#include <stdio.h>
13
14
15
16
17
18
19
20
21
22
23
24
int
int
int
int
struct datiCliente{
int numConto;
char cognome[15]; char nome[10];
float importo;
};
1. Definisce la struttura
che rappresenta un
blocco di dati (record)
dei due file
int inserisciScelta(void);
scriviFileStampa(FILE *);
aggiornaConto(FILE *);
creaConto(FILE *);
cancellaConto(FILE *);
int main(){
FILE *cfPtr;
int scelta;
if((cfPtr = fopen(“conti.dat","r+")) == NULL)
printf(“Impossibile aprire il file.\n");
else{
 2000 Prentice Hall, Inc. All rights reserved.
2. Prototipi funzioni
3. Apre il file ad accesso
diretto di riferimento
“conti.dat” con i dati
dei conti (quello poi
passato alle funzioni)
11.11 - Caso di studio: programma per
elaborare delle transazioni (3/8)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 }
45
46
while( (scelta = inserisciScelta()) != 5 ){
switch( scelta ) {
case 1:
scriviFileStampa( cfPtr );
break;
case 2:
aggiornaConto( cfPtr );
break;
case 3:
creaConto( cfPtr );
4. Acquisisce la scelta
dell’operazione da
eseguire
break;
case 4:
cancellaConto( cfPtr );
break;
}
}
fclose( cfPtr );
}
return 0;
 2000 Prentice Hall, Inc. All rights reserved.
5. Chiude il file dei conti
che è stato aperto
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 };
50
51
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 }
67
68
 2000 Prentice Hall, Inc. All rights reserved.
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”
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 };
72
73
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
80
81
82
83
84
85
86
87
88
89
90 }
else{
printf( "%-6d%-16s%-11s%10.2f\n\n", cliente.numConto,
cliente.lastName, cliente.nome, cliente.importo );
printf( “Inserire accredito ( + ) o pagamento ( - ): " );
scanf( "%lf", &variazione );
cliente.importo += variazione;
printf( "%-6d%-16s%-11s%10.2f\n", cliente.numConto,
cliente.cognome, cliente.nome, cliente.importo );
fseek(fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET);
fwrite( &cliente, sizeof( struct datiCliente ), 1, fPtr );
}
 2000 Prentice Hall, Inc. All rights reserved.
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
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 };
94
95
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 }
106
107 void creaConto( FILE *fPtr ){
108
int conto;
109
struct datiCliente cliente = { 0, "", "", 0.0 };
110
111
printf( “Inserire il numero del nuovo conto(1 - 100): ");
112
scanf( "%d", &conto );
 2000 Prentice Hall, Inc. All rights reserved.
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
11.11 - Caso di studio: programma per
elaborare delle transazioni (7/8)
113
114
115
116
117
118
119
120
121
122
seek( fPtr,(conto - 1) * sizeof(struct datiCliente),SEEK_SET );
fread( &cliente, sizeof( struct datiCliente ), 1, fPtr );
if( cliente.numConto != 0 )
printf( “Il conto #%d esiste già.\n", conto );
else{
printf( “Inserire cognome, nome, importo\n? " );
scanf( "%s%s%lf", &cliente.cognome, &cliente.nome,
&cliente.importo );
cliente.numConto = conto;
fseek(fPtr, (cliente.Numconto - 1)
123
* sizeof(struct datiCliente), SEEK_SET);
124
fwrite( &cliente, sizeof( struct datiCliente ), 1, fPtr );
125
}
126 }
127
128 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 }
 2000 Prentice Hall, Inc. All rights reserved.
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
11.11 - Caso di studio: programma per
elaborare delle transazioni (8/8)
<Dopo aver scelto l’opzione 1, il file conti.txt contiene>
Conto
29
33
37
88
96
Cognome
Brown
Dunn
Barker
Smith
Stone
Nome
Nancy
Stacey
Doug
Dave
Sam
Importo
-24.54
314.33
0.00
258.34
34.98
Inserire il numero di conto da modificare(1-100): 37
37
Barker
Doug
0.00
Inserire accredito (+) o pagamento (-): +87.99
37
Barker
Doug
87.99
Insrire il numero del nuovo conto(1-100): 22
Inserire cognome, nome, importo
? Johnston Sarah 247.45
 2000 Prentice Hall, Inc. All rights reserved.
Visualizzazione
del programma
Fly UP