Cosa sono i file? Un file è un archivio di dati che puo essere registrato su un supporto di massa (testo, lettera, programma, archivio di dati, ecc.) Fondamenti di Informatica 12. Linguaggio C - Gestione di file Il file è l unità logica di memorizzazione dei dati su dispositivi di memoria di massa Il file permette: una memorizzazione persistente dei dati una memorizzazione non limitata dalle dimensioni della memoria centrale Un file si puo anche considerare come un insieme di record correlati tra loro (ossia un insieme di informazioni strutturate e organizzate in un archivio) similitudine con le tabelle (array di strutture) Corso di Laurea in Ingegneria Informatica e dell Automazione A.A. 2012-2013 2 Semestre Prof. Giovanni Pascoschi Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 2 Tipiche operazioni su file Tipi di file (di testo e binari) Apertura del file : si stabilisce un collegamento logico tra la memoria centrale e l unità di memoria di massa che contiene il file sul quale si vogliono fare operazioni di lettura/scrittura viene riservata un area di memoria centrale buffer di I/O Chiusura del file : si chiude il collegamento logico tra la memoria centrale e l unità di memoria di massa che contiene il file (eseguito dopo la relativa apertura) Lettura dal file : si trasferiscono i dati dal file alla memoria centrale (input da file) Scrittura sul file : si trasferiscono i dati dalla memoria centrale al file (output su file) La tipologia di file di testo deriva essenzialmente dalla loro leggibilità File di testo (o ASCII) : i file di testo contengono i caratteri di fine riga (EOL End Of Line) e a ciascun byte corrisponde un carattere codificato in ASCII facilmente leggibili (vecchio approccio) Esempio: file sorgenti, bolle/fatture nei vecchi programmi Notepad File binari : i file binari sono considerati come un unico flusso continuo di bit, anch essi raggruppati in byte, ma non necessariamente distinti l uno dall altro (moderno approccio) Esempio : file eseguibili, documenti Word/Excel, ecc Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 3 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 4
Modalità di accesso ai file File con record a lunghezza fissa/variabile Accesso sequenziale: in fase di lettura i dati possono essere ritrovati (sequenzialmente) scorrendo tutti i record del file a partire dal primo fino ad arrivare all ultimo, nello stesso ordine con il quale sono stati registrati Accesso diretto (random/casuale): nel caso di utilizzo di record a lunghezza fissa aventi pertanto la stessa struttura, l accesso in lettura alla specifica componente puo avvenire direttamente, identificando la sua posizione all interno del file Record a lunghezza fissa: Nelle maggior parte delle applicazioni gestionali gli archivi nelle memorie di massa interessano file formati da record aventi la stessa struttura (record a struttura fissa/lunghezza fissa) sia accesso sequenziale che diretto Record a lunghezza variabile: In alcune applicazioni particolari i record non hanno lunghezza fissa (p.e. file sorgenti in cui le singole righe terminano con un EOL) solo accesso sequenziale Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 5 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 6 Esempio Dichiarazione del file struct Persona { char indirizzo[20]; float stipendi[12]; ; typedef struct Persona dip; dip Dipendente;... La dichiarazione di un file avviene con la seguente sintassi: FILE * fp; puntatore a una struttura di informazioni che si riferiscono al file utilizzato (p.e. locazione del buffer I/O, posizione corrente nel buffer durante la lettura e scrittura, ecc.) Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 7 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 8
Apertura del file Modalità di accesso al file La sintassi per l apertura di un file è la seguente: fp = fopen( nomefisico, modalità ); fp è il puntatore al file o descrittore del file (nome interno del file) nomefisico è il nome del file sul supporto di massa (attenzione percorso!) modalità indica le modalità di accesso al file se fp ritorna un valore NULL significa che ci sono stati del problemi ad aprire il file N.B.: una volta che si apre un file, esso rimane aperto finchè non viene chiuso esplicitamente dal programma o quando il programma stesso termina file binari file di testo modalità commenti rb r solo lettura wb w solo scrittura r+b r+ lettura & scrittura w+b w+ scrittura & lettura ab a a+b a+ se il file non esiste, restituisce un messaggio di errore se il file non esiste, viene creato; se esiste viene effettuata la sovrascrittura a partire dall inizio con perdita dei dati precedenti se il file non esiste, viene creato; se scrittura in fondo al esiste viene effetuata la scrittura in coda file (append) ai dati già esistenti scrittura in fondo al file e lettura Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 9 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 10 Esempio Chiusura del file struct Persona { char indirizzo[20]; float stipendi[12]; ; typedef struct Persona dip; dip Dipendente; int main() { fp = fopen( registro.dat, w );... /*apertura in sola scrittura del file chiamato registro.dat di tipo testuale*/ La sintassi per la chiusura di un file è la seguente: alla fine di una sessione di accesso al file è necessario chiuderlo per memorizzare permanentemente il suo contenuto nel dispositivo di memoria di massa all esecuzione di fclose viene assegnato NULL a fp e si rilascia il descrittore di tipo FILE la funzione restituisce 0 se l operazione di chiusura avviene correttamente, altrimenti restituisce EOF (End Of File) Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 11 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 12
Lettura di un record dal file Questa istruzione permette di leggere una componente dal file (record) e ne trasferisce il contenuto nella memoria centrale con la seguente sintassi: fread(&buffer, dimensione, numero_elementi, fp); buffer è il buffer di I/O dimensione indica la quantità di byte da leggere complessivamente per ciascun record numero_elementi indica la quantità di record da leggere se indichiamo numero_elementi > 1 possiamo leggere piu record contemporaneamente supponendo di avere una tabella (array di strutture) Esempio struct persona { char indirizzo[20]; float stipendi[12]; ; typedef struct persona dip; dip dipendente; int main() { fp = fopen( registro.dat, r ); fread(&dipendente, sizeof(struct persona), 1, fp);... // lettura di un record dal file Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 13 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 14 Scrittura di un record su file Esempio Questa istruzione permette di scrivere una componente dal file (record) e ne trasferisce il contenuto dalla memoria centrale alla memoria di massa con la seguente sintassi: fwrite(&buffer, dimensione, numero_elementi, fp); buffer è il buffer di I/O dimensione indica la quantità di byte da leggere complessivamente per ciascun record numero_elementi indica la quantità di record da scrivere N.B.: ad ogni scrittura il puntatore al file si sposta in avanti di tanti byte quanti sono gli elementi registrati moltiplicati per la dimensione del record struct persona { char indirizzo[20]; float stipendi[12]; ; typedef struct persona dip; dip dipendente; int main() { fp = fopen( registro.dat, w ); fwrite(&dipendente, sizeof(struct persona), 1, fp); su file... // scrittura di un record Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 15 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 16
Posizionamento del puntatore Verifica Fine file Il file si puo assimilare a un nastro video/audio Questa istruzione permette di verificare se si è raggiunto la fine del fine EOF (End Of File) con la seguente sintassi: feof(fp); inizio del file posizione fine del file corrente La posizione corrente indica il punto da si leggerà (o si scriverà) L indicatore di posizione corrente si sposta in avanti dopo ogni lettura/scrittura Esistono le operazioni per spostare la posizione corrente in avanti o indietro senza leggere o scrivere (per esempio, fseek) Il file non ha dimensioni prefissate. La sua dimensione massima dipende dalla dimensione della memoria di massa la funzione restituisce falso (0) se non si è raggiunta la fine del file la funzione restituisce vero (!=0) se si è raggiunta la fine del file Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 17 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 18 Posiziona il puntatore Questa istruzione (usata per l accesso diretto) permette di posizionare il puntatore ad una specifica componente del file calcolando il numero di byte dei record che lo precedono con la seguente sintassi: fseek(fp, posizione, inizio); posizione è il numero di byte con il quale il puntatore viene spostato inizio (long) puo assumere tre valori : SEEK_SET 0 posizionamento a partire dall inizio del file SEEK_CUR 1 posizionamento a partire dalla posizione corrente del puntatore SEEK_END 2 posizionamento a partire dalla fine del file Ritorna il valore di posizionamento del puntatore Questa istruzione permette di determinare la posizione corrente del puntatore al file con la seguente sintassi: long pos; pos = ftell(fp); N.B.: nel caso di apertura del file in r+, w+ o a+, nel passaggio da una tipologia di accesso (readwrite o writeread) bisogna utilizzare fseek(fp, 0, SEEK_CUR) per fissare il puntatore al record Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 19 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 20
Gestione degli errori Esempio Accesso Sequenziale (1) La funzione ferror(fp) restituisce: 0 se non è stato commesso alcun errore nella precedente operazione di lettura/scrittura un valore!=0 in caso contrario struct persona { ; typedef struct persona dip; dip dipendente; void registra(void); void visualizza(void); Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 21 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 22 Esempio Accesso Sequenziale (2) int main( ) { // registrazione fp = fopen( registro.dat, wb ); registra( ); // visualizzazione fp = fopen( registro.dat, rb ); if( fp!= NULL) { visualizza( ); else cout<< Errore: l archivio non esiste <<endl; return 0; Esempio Accesso Sequenziale (3) void registra() { int risposta; do { print( Inserimento di un dipendente \n ); printf( Matricola: \n ); scanf( %d,&dipendente.matricola); printf( Cognome: \n ); scanf( %s,dipendente.cognome); printf( Nome:\n ); scanf(( %s,dipendente.nome); printf( Livello: ); scanf( %d,&dipendente.livello); fwrite(&dipendente, sizeof(dip), 1, fp); printf( Elenco finito? (0 = no, 1 = si): \n ); scanf( %d,&risposta); while(!risposta); return; Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 23 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 24
Esempio Accesso Sequenziale (4) void visualizza() { printf( Elenco dipendenti \n ); fread(&dipendente, sizeof(dip), 1, fp); while(!feof(fp)) { printf( Matricola:\n ); printf( %d, dipendente.matricola); printf( Cognome: \n ); printf( %s, dipendente.cognome); printf( Nome: \n ); printf( %s, dipendente.nome); printf( Livello:\n ); printf( %d, dipendente.livello); fread(&dipendente, sizeof(dip), 1, fp); return; Esempio Accesso Diretto (1) struct persona { ; typedef struct persona dip; dip dipendente; void registra(void); Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 25 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 26 Esempio Accesso Diretto (2) Esempio Accesso Diretto (3) int main( ) { // registrazione fp = fopen( registro.dat, a+b ); if( fp!= NULL) { registra( ); else printf( Errore: l archivio non esiste \n ); return 0; void registra() { int i; long posizione; printf( Inserimento di un dipendente \n ); printf( inserire indice record inserire il dipendente \n ); scanf( %d, &i); while(i > 0) { posizione = (i 1) * sizeof(dip); fseek(fp, posizione, 0); if( fread(&dipendente, sizeof(dip), 1, fp) && dipendente.cognome[0]!= \0 ) { printf( Attenzione codice gia presente\n ); printf( Matricola: \n ); scanf( %d, &dipendente.matricola); printf( Cognome: \n ); printf( %s, dipendente.cognome); printf( Impossibile registrazione \n ); Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 27 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 28
Esempio Accesso Diretto (4) File di record a lunghezza variabile else { printf( Matricola: \n ); scanf( %d, &dipendente.matricola); printf( Cognome: \n ); scanf( %s,dipendente.cognome); printf( Nome:\n ); scanf(%s,dipendente.nome); printf( Livello: \n ); scanf( %d, &dipendente.livello); fseek(fp, posizione, 0); fwrite(&dipendente, sizeof(dip), 1, fp); printf( inserire indice record inserire il dipendente (0 termina) \n ); scanf( %d, &i); return; Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 29 I file sorgenti sono un esempio di file con record a lunghezza variabile: ogni riga termina con un EOL (End Of Line) in genere sono file di testo l accesso puo essere solo di tipo sequenziale Tipiche istruzioni per lettura/scrittura file di testo a lunghezza variabile: fprintf(fp, %s \n,nome); fscanf(fp, %s, nome); // scrittura su file // lettura da file N.B. : si ricorda che nel caso in cui al posto di fp si usa stdprn, la fprintf gestisce il flusso verso la stampante Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 30 Esempio di file di record a lunghezza variabile File *fp; void chiedi( ); int main( ) { fp = fopen( rubrica.txt, w ); chiedi ( ); while ( nome[0]!= * ) { fprintf (fp, %s \n, nome); chiedi ( ); return 0; void chiedi ( ) { printf( inserisci il nome di un collega ( * per finire) \n ); scanf( %s,nome); return; File di record a lunghezza variabile per gestire i singoli caratteri si usano le istruzioni: c = fgetc(fp1); // equivalente alla fscanf di un carattere fputc(c, fp1); // equivalente alla fprintf di un carattere per gestire le righe intese come stringhe si usano le istruzioni: fgets(buf, n, fp1); // legge fa file una riga di n caratteri e la mette in buf fputs(buf, fp1); // scrive una riga su file Esempio : copia di due file binari byte per byte Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 31 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 32
Esempio di file di record a lunghezza variabile Riepilogo della lezione int main( ) { File *fp1, *fp2; int a; fp1 = fopen( file1.doc, rb ); fp2 = fopen( file2.doc, wb ); a = fgectc(fp1); while (! feof(fp1)) { fputc( c, fp2); a = fgetc(fp1); fclose(fp1); fclose(fp2) return 0; Linguaggio C - Gestione dei file File di testo e binari Operazioni su file con accesso sequenziale Operazioni su file con accesso diretto Esempio di file con accesso sequenziale Esempio di file con accesso diretto File di record a lunghezza variabile Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 33 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 34 Fine della lezione Domande? Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 35