04.5-Linguaggio C - Gestione dei file [modalità compatibilità]
Transcript
04.5-Linguaggio C - Gestione dei file [modalità compatibilità]
Università degli Studi di Cagliari Corso di Laurea in Ingegneria Biomedica (Industriale), Chimica, Meccanica, Elettrica Sommario FONDAMENTI DI INFORMATICA 1 http://www.diee.unica.it/~marcialis/FI1 Scrivere e leggere da qualunque I/O Il tipo FILE Funzioni fscanf e fprintf EOF A.A. 2010/2011 Funzioni sscanf e sprintf Docente: Gian Luca Marcialis LINGUAGGIO C Gestione dei file Il tipo FILE Passaggio da standard I/O Lo stato della “macchina virtuale C” dopo la lettura di due valori numerici dalla tastiera Bus di sistema 12 28 CPU 12 28 &a &b &somma Locazioni libere Standard Input Standard Output E’ un particolare tipo, che serve ad identificare appunto I/O diverso da “standard I/O” Una variabile di tipo FILE identifica univocamente una “lavagna” (“stream”) nella quale si possono scrivere informazioni o cercarne (“leggerne”), se presenti Le funzioni per gestire i file sono presenti nella libreria <stdio.h> Per definire una variabile di tipo FILE: FILE *fp; Funzioni per gestire i file fp = fopen(char* NomeFile, char* Modalità) “Apre” lo “stream” identificato da fp (assegnandogli un valore) NomeFile è una stringa con il nome del file. Es. NomeFile=“pippo.txt” Modalità è una stringa di uno o due caratteri: − “w” se il file è aperto in scrittura − “r” se è aperto in lettura − “a” se è aperto in modalità “append”, ovvero si vogliono aggiungere ai contenuti presenti nuovi contenuti scritti “in fondo” al file L’uscita di fopen() è una costante di valore NULL se il file aperto in lettura/append non esiste oppure c’è un errore nel nome del file. int fclose(FILE *fp) E’ la funzione che chiude il file dopo che su esso sono state compiute le operazioni desiderate, restituendo un valore diverso da 0 se l’operazione è andata a buon fine Un file va sempre chiuso al termine del suo utilizzo Esercizio Scrivere una funzione C scriviVettore, che, ricevendo in ingresso una stringa NomeFile e un vettore di N interi v, scriva il contenuto su un file di nome indicato da NomeFile, andando a capo per ogni valore scritto La funzione deve restituire il valore 1 se l’operazione è andata a buon fine, 0 altrimenti Scrittura/lettura su file fprintf(FILE *fp, *StringaDaScrivere, parametri) char E’ l’analogo di printf per i file, si usa esattamente nella stessa maniera Es. fprintf(fp,”L’area del cerchio è pari a %f.\n”,area); − Scrive la stringa tra virgolette sul file aperto identificato da fp fscanf(FILE *fp, EspressioneDaLeggere, parametri) Analogo di scanf per i file Es. fscanf(fp,”%d %d”,&a,&b); char* − Si aspetta di legge due valori interi da file e li memorizza nelle variabili a e b Soluzione int scriviVettore(char* NomeFile, int* vettore, int N) { FILE *fp; int i; fp=fopen(NomeFile,”w”); if (fp==NULL) return 0; for (i=0; i<N; i++) fprintf(fp,”%d\n”,v[i]); fclose(fp); return 1; } Gestione degli errori nei file int feof(FILE *fp) Controlla nella struttura di descrizione dello stato del file cui fa riferimento fp se è stata raggiunta la fine del file nella precedente operazione di lettura o scrittura Restituisce 0 se la condizione di fine file non è stata raggiunta, un valore diverso da 0 in caso contrario Esercizio Scrivere un programma che legge da file una sequenza di interi, separati da spazi o “a capo”, e la memorizza in un vettore. Il nome del file viene fornito da tastiera. Il vettore può avere al massimo 50 valori, ma il file presenta un numero di interi non definito. Si stampi a video eventualmente un avviso se la lunghezza massima del vettore è stata raggiunta interrompendo l’acquisizione di valori Si stampi a video infine il vettore acquisito. Soluzione /*Programma che legge max 50 interi da file e li memorizza in un vettore*/ #include <stdio.h> int main() { int i, j, vettore[50]; char nomefile[100]; FILE *fp; printf(“Inserire il nome del file:\n”); scanf(“%s”,nomefile); fp=fopen(nomefile,”r”); i=0; while((!feof(fp))&&(i<50)) /*finché il file non è finito e i<50*/ { fscanf(fp,”%d”,&vettore[i]); i=i+1; /* oppure i++; */ } if(i==50) printf(“\nMax numero di valori acquisibile raggiunto.\n”); fclose(fp); for(j=0; j<i; j++) printf(“\nv[%d] = %d”,vettore[j]); return 0; } Scrittura e lettura su stringhe sprintf(char* StringaDiScrittura, *StringaDaScrivere, parametri); char Analoga a printf e fprintf, solo che scrive nella stringa indicata da StringaDiScrittura, finché c’è spazio Es. sprintf(frase,”Il perimetro del rettangolo è %f.\n”,perimetro); − Scrive nella stringa frase l’espressione tra virgolette sscanf(char* StringaDiLettura, char* EspressioneDaLeggere, parametri); Ulteriori funzioni per manipolare stringhe sono presenti nella libreria <string.h> Alcune funzioni utili di <string.h> char* strcpy(s,ct) Copia la stringa ct nella stringa s, incluso ‘\0’; restituisce s char* strcat(s,ct) Concatena la stringa ct alla fine della stringa s; restituisce s int strcmp(cs,ct) Confronta la stringa cs con la stringa ct; restituisce <0 se cs<ct, 0 se cs==ct, >0 se cs>ct size_t strlen(cs) Restituisce la lunghezza di cs Esempio di file geometri.txt Triangolo 34.2 45.1 90.4 Rettangolo 40.1 20.9 Rettangolo 12.1 55.5 Quadrato 45.0 Esercizio Scrivere un programma che legge un file di testo geometri.txt così formattato: <Forma Geometrica> v1 [v2 v3] Dove <Forma Geometrica> = Triangolo Rettangolo v1 [v2 v3] sono al massimo tre valori reali | Quadrato | Per ogni riga di ingresso, il programma calcola e scrive, nel file di uscita risultati.txt, ed in modalità “append”, la forma della figura e il suo perimetro Si sviluppi la soluzione in forma modulare Attraverso procedure e funzioni Vincoli per scrivere la soluzione Si definisca una struttura dati Forma_Geometrica, caratterizzata da: un vettore di caratteri nome_forma indicanti il tipo (“Triangolo”; “Quadrato”; “Rettangolo”); un vettore di float lati di max 3 posizioni con i valori dei lati un valore float perimetro; un intero numero_lati tale che: − − − − Se 1 la forma è “Quadrato” Se 2 la forma è “Rettangolo” Se 3 la forma è “Triangolo” Altrimenti la forma non è definita, e contenga il valore 0; Si scriva inoltre: una funzione che calcoli il perimetro per ognuna delle tre forme: essa riceve in ingresso il vettore dei lati ed il numero di lati, e restituisce un valore reale pari al perimetro una funzione che legga il tipo di forma da file, calcoli il numero opportuno di lati restituisca una variabile di tipo Forma_Geometrica aggiornata una funzione che, ricevendo in ingresso una variabile di tipo Forma_Geometrica, scriva la forma e stampi il perimetro nel file su file in modalità “append” Definizione della struttura dati richiesta typedef struct { char nome_forma[50]; float lati[3]; float perimetro; int numero_lati; } Forma_Geometrica; Implementazioni delle funzioni richieste: perimetro della forma float perimetro_forma(float *lati, int num_lati) { switch(num_lati) { case 1: return 4*lati[0]; case 2: return 2*(lati[0]+lati[1]); case 3: return lati[0]+lati[1]+lati[2]; } return 0.0; } Aggiornamento della forma Forma_Geometrica leggi_forma(FILE *fp) { int i; Forma_Geometrica forma; fscanf(fp,”%s”,&(forma.nome_forma[0])); if(!strcmp(forma.nome_forma,”TRIANGOLO”) forma.numero_lati=3; else if(!strcmp(forma.nome_forma,”RETTANGOLO”) forma.numero_lati=2; else if(!strcmp(forma.nome_forma,”QUADRATO”) forma.numero_lati=1; else { forma.numero_lati=0; printf(“\nForma non definita\n”); } for(i=0; i<forma.numero_lati; i++) fscanf(fp,”%d”,&(forma.lati[i])); return forma; } Stampa della forma col perimetro void stampa_forma(Forma_Geometrica forma) { FILE *out; out=fopen(“risultati.txt”,”a”); if(out==NULL) return; fprintf(out,“%s %f\n”,forma.nome_forma,forma.perimetro); fclose(out); } Soluzione: vista top-down /*Apri il file geometri.txt*/ /*Programma per la stampa del perimetro di una forma geometrica su file*/ #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *in; Forma_Geometrica forma; /*Apri il file geometri.txt */ while (!feof(in)) /* Finché il file non è finito*/ { /*Leggi la forma geometrica*/ /*Se la forma è definita: Calcola il perimetro della forma letta Stampa il perimetro della forma su file risultati.txt Altrimenti Esci dal ciclo*/ } /*Chiudi il file geometri.txt*/ in=fopen(“geometri.txt”,”r”); if(in==NULL) return 0; /*Chiudi il file geometri.txt*/ fclose(in); return 0; } Ritorniamo al main /*Programma per la stampa del perimetro di una forma geometrica su file*/ #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE *in; Forma_Geometrica forma; in=fopen(“geometri.txt”,”r”); if(in==NULL) return 0; while (!feof(in)) /* Finché il file non è finito*/ { forma=leggi_forma(in); if(forma.num_lati!=0) { forma.perimetro=perimetro_forma(forma.lati,forma.numero_lati); stampa_forma(forma); } else break; } fclose(in); return 0; } Per saperne di più Ceri, Mandriola, Sbattella, Informatica – arte e mestiere, Capp.3-4, McGraw-Hill Kernighan, Ritchie, Il linguaggio C, Cap. 1, PearsonPrentice Hall