FILES


pagine di Roberto Ricci L.S. "A. Righi", Bologna. Ultima revisione


 
 
 
 

File binari


  Un file binario è un flusso di byte, una sequenza di unità d'informazione non interpretate, che quindi possono rappresentare qualunque informazione (testi, numeri, immagini...).
Nel file stdio.h sono dichiarate in particolare le function:
fopen()             	Apre il file                                               
fclose()            	Chiude il file
fread()   		Legge dal file
fwrite()                Scrive sul file  
fgetc()                 Legge il prossimo byte del file
fputc()                 Scrive un carattere nel file   
fseek()                 Scorre lungo il file
ftell()                 restituisce la posizione attuale nel file        
Tra queste, per aprire il file che ha nome nomefile da associare a un flusso di dati,
FILE *fopen(char *nomefile, char *mode);
in cui la stringa mode può avere i seguenti valori:
                                  
"rb"                Apre un file binario per la lettura                              
"wb"                Crea un file binario per la scrittura                            
"ab"                Appende a un file binario                                     
"r+b"               Apre un file binario per la lettura/scrittura                           
"w+b"               Crea un file binario per la lettura/scrittura                         
"a+b"               Apre o crea un file binario per la lettura/scrittura                 
Su un file è possibile scrivere informazione mediante:
int fwrite(nomevariabile, int dimensione, int numero elementi, FILE *nomefile);
per scrivere dal file un certo numero di elementi di dimensione dichiarata in byte a partire dall'indirizzo della variabile indicata. Restituisce il numero di elementi (non di byte) effettivamente scritti, eventualmente meno di n se il file finisce prima.
Importante è anche la chiusura del file con:
FILE *fclose(char *nomefile);
  1. Redigere ed eseguire il programma seguente per creare eventualmente e aprire un file binario e scrivervi un vettore di 10 numeri interi
    #include <stdio.h>
    
    main(){
    	FILE *fp;		// Dichiara una variabile del tipo flusso d'informazione
    	fp = fopen ("a:numeri.dat", "wb");	// Associa a tale flusso un file su disco
    	if (fp == NULL){
    		printf ("errore di apertura \n");
    	}else{
    		int vet[13] = {1,2,3,4,5,6,7,8,9,10,11,12,13};
    		fwrite (vet, sizeof(int), 13, fp);
    		fclose(fp);
    	}
    }
    
  2. Visualizzare l'elenco dei file presenti sul disk A: controllando che tra questi compaia numeri.dat
  3. Aprire con il Blocco note il file numeri.dat ([Tasto destro del mouse]Nuovo|Documento di testo e trascinare sul foglio vuoto l'icona di numeri.dat) verificandone l'illegibilità
  4. Redigere ed eseguire il programma seguente per leggere il file binario numeri.dat mediante la function
    int fread(&nomevariabile, int dimensione, int numero elementi, FILE *nomefile);
    
    per leggere dal file un certo numero di elementi di dimensione dichiarata in byte componenti la variabile della quale viene indicato l'indirizzo. Restituisce il numero di elementi (non di byte) effettivamente letti, eventualmente meno di n se il file finisce prima.
    #include <stdio.h>
    
    main(){
    	FILE *fp;
    	fp = fopen ("a:numeri.dat", "rb");
    	if (fp == NULL){
    		printf ("errore di apertura \n");
    	}else{
    		int vett[100];
    		int i=0;
    		while(fread(&vett[i],sizeof(int),1,fp)>0){
    		  printf("%d\n",vett[i]);
    		}
    		fclose(fp);
    	}
    }
    
  5. Modificare i precedenti programmi in modo che il file dei dati si riferisca a tipi float
  6. Modificare i precedenti programmi in modo che si debba dichiarare il tipo di dato
  7. Realizzare un programma che proponga un menu: crea, leggi, cancella, aggiungi dati (da inserire da tastiera)

 
 
 

File testo


  I file binari sono sufficienti a qualunque scopo. Tuttavia, per la gestione di sequenze di caratteri, viene offerta una grande comodità, quella dei file di testo. Infatti nei file di testo L'apertura e la chiusura dei file si fanno come già visto, cambia solo per l'apertura la stringa mode, che in questo caso può avere i valori:
                                                
"r"                 Apre un file testo per la lettura                                
"w"                 Crea un file testo per la scrittura                              
"a"                 Appende a un file testo                                        
"r+"                Apre un file testo per la lettura/scrittura                             
"w+"                Crea un file testo per la lettura/scrittura                           
"a+"                Apre o crea un file testo per la lettura/scrittura                   
"rt"                Apre un file testo per la lettura                                
"wt"                Crea un file testo per la scrittura                              
"at"                Appende a un file testo                                       
"r+t"               Apre un file testo per la lettura/scrittura                             
"w+t"               Crea un file testo per la lettura/scrittura                           
"a+t"               Apre o crea un file testo per la lettura/scrittura                   
I canali di I/O standard non sono altro che file di testo già aperti: Le funzioni di I/O disponibili per i file di testo sono una generalizzazione di quelle già note per i canali di I/O standard.
Nel file stdio.h sono dichiarate in particolare le function:
                                             
    da console 				da file                             

int getchar(void); 		int fgetc(FILE* f);                         
int putchar(int c); 		int fputc(int c, FILE* f);
char* gets(char* s); 		char* fgets(char* s, int n, FILE* f);
int puts(char* s); 		int fputs(char* s, FILE* f);
int printf( ... ); 		int fprintf(FILE* f, ... );
int scanf( ... ); 		int fscanf(FILE* f, ... );
  1. Redigere ed eseguire il seguente programma per salvare su un file di testo ciò che viene battuto sulla tastiera (utilizzare la combinazione di tasti [Ctrl]+Z per terminare l'immissione dei dati).
    #include <stdio.h>
    
    main(){
    	FILE *fp;
    	fp = fopen ("a:testo.txt", "wt");
    	char car;
    	if (fp != NULL){
    		car=getchar();
    		while (car!=EOF){
    			fputc(car, fp);
    			car=getchar();
    		}
    		fclose(fp);
    	}else{
    		printf ("errore di apertura del file in scrittura");
    	}
    }
    
  2. Visualizzare l'elenco dei file presenti sul disk A: controllando che tra questi compaia testo.txt
  3. Leggere il contenuto di testo.txt
  4. Modificare tale file testo con gli strumenti di editoria del Blocco note
  5. Redigere ed eseguire il seguente programma per stampare a video il contenuto di un file testo
    #include <stdio.h>
    
    main(){
    		FILE *fp;
    		int car;
    		fp = fopen ("a:testo.txt", "rt");
    		if (fp != NULL){
    			do{
    				car=fgetc(fp);
    				putchar(car);
    			}while (car!=EOF);
    			fclose(fp);
    		}else{
    			printf ("errore di apertura del file in lettura");
    		}
    }
  6. Scorrere un file, ovvero riposizionare il 'file pointer' in uno stream, mediante la function
    int fseek(FILE *nomefile, long numero, int opzione);
    
    la nuova posizione è un certo numero di byte dalla collocazione iniziale fissata dall'opzione tra le seguenti possibili:
    Costante 	opzione		Collocazione iniziale
    
    SEEK_SET	0		inizio File
    SEEK_CUR	1		posizione corrente
    SEEK_END	2		End-of-file
    
    che restituisce il valore 0 se l'azione ha successo, un valore non nullo atrimenti.
    #include <stdio.h>
    
    main(){
    		FILE *fp;
    		char car;
    		fp = fopen ("a:testo.txt", "r+");
    		if (fp != NULL){
    			do
    				car=fgetc(fp);
    			while (car!='a');
    			fseek(fp,-1,SEEK_CUR);
    			fputc('X',fp);
    			fclose(fp);
    		}else{
    			printf ("errore di apertura del file in lettura/scrittura");
    		}
    }
    
  7. Modificare il precedente programma in modo da sostituire tutte le occorrenze di una dato carattere con un altro carattere dato.
  8. Per ottenere la posizione raggiunta all'interno del file, il file pointer corrente, si può usare la function:
    long int ftell(FILE *stream);
    
    Tale posizione è il n° di bytes dall'inizio del file oppure -1L in caso di errore.
    Redigere ed eseguire il seguente programma che restituisce la lunghezza, in byte, di un file
    #include <stdio.h>
    
    main(){
    		FILE *fp;
    		fp = fopen ("a:testo.txt", "rt");
    		if (fp != NULL){
    			fseek(fp,0L,SEEK_END);
    			printf ("numero di caratteri del file: %ld",ftell(fp));
    			fclose(fp);
    		}else{
    			printf ("errore di apertura del file in lettura");
    		}
    }
    
  9. Modificare il programma per la lettura di un file di testo in modo da richiedere in input il nome del file.
  10. Realizzare un programma che verifichi se una certa parola è contenuta in un file di testo.

 
 
 

Strutture


  Oltre ai tipi di dato semplici, predefiniti come int, char, float, double, ... ( ma anche definibili dall'utente con il costruttore 'enum') vi sono altri tipi di dato, strutturati come quelli che si ottengono mediante il costruttore [] (array), definiti con il costruttore struct.
struct nomeStruttura {
	 definizione di componente ;
	 definizione di componente ;
	 ..........
	 definizione di componente ;
};
Ad esempio per definire la struttura:
struct persona {
	char cognome[20];
	char nome[20];
	char sesso:
	int anno;
};
oppure per definire un identificatore di tipo di dato strutturato:
 
typedef struct {
 	float x;
 	float y;
 	float z;
} punto;
mentre per dichiarare variabili di quel tipo:
struct persona tizio={"mario", "rossi", 50};
struct persona caio;
caio={"pippo", "bianchi", 3};
punto P={0,1,0};
Una volta definita una variabile strutturata, si accede ai singoli campi mediante la notazione puntata. Ad esempio:
media=(caio.eta + tizio.eta)/2;
somma=P.x + P.y + P.z;
P.x=0;
  1. Redigere ed eseguire il seguente programma per aggiungere altri dati in un file a:archivio.txt già contenente i dati:
    Rossi Bianca F 1947
    Bianchi Viola F 1982
    Violetti Azzurra F 1976
    Azzurri Celestino M 1988
    Celesti Rosa F 2000
    
    .
    #include <stdio.h>
    
    typedef struct{
    	char cognome[20];
    	char nome[20];
    	char sesso;
    	int anno;
    } persona;
    
    main(){
    	FILE *fp;
    	fp = fopen ("a:archivio.txt", "at");
    	persona p;
    	if (fp == NULL){
    		printf ("errore di apertura \n");
    	}else{
    		int si=1;
    		do{
    			printf("\nCognome:  "); scanf("%s",p.cognome);
    			printf("\nNome:  "); scanf("%s",p.nome);
    			printf("\nSesso:  "); scanf("%s",&p.sesso);
    			printf("\nAnno:  "); scanf("%d",&p.anno);
    			fprintf (fp, "\n%s %s %c %d",p.cognome, p.nome, p.sesso, p.anno);
    			printf("\nAncora dati da inserire? (1=si 0=no)  "); scanf("%d",&si);
    		}while (si);
    		fclose(fp);
    	}
    }
    
  2. Scrivere un programma che cerchi nell'archivio se vi sono persone con un dato cognome
  3. A differenza di quanto accade con gli array, il nome della struttura rappresenta la struttura nel suo complesso. Quindi si possono fare assegnazioni tra strutture o realizzare function che hanno per valore una struttura; si può inoltre passare una struttura come parametro a una funzione (passaggio per valore).
    Completare il programma seguente per le trasformazioni nel piano.
    #include <stdio.h>
    
    typedef struct {float x, y;} punto;	// di coordinate (x;y)
    typedef struct {float a, b, c;} retta; // di equazione ax+by+c=0
    
    punto traslaz(punto, punto);
    punto simm(punto,punto);
    punto simmAss(punto,retta);
    punto rotaz(punto,punto,float);
    
    punto leggiPto();
    retta leggiRetta();
    
    main(){ 
    	punto P=leggiPto();
    	unsigned int op;
    	printf("\nTrasformazioni:\n1: traslazione;2\n simmetria centrale;");
    	printf("\n3 simmetria assiale:\n4: rotazione;\n\n scelta ?");
    	scanf("%d",&op);
    	switch (op){
    	case1 : 	
                	printf ("Corrispondente di O(0,0) nella traslazione ?");
    		punto T=leggiPto();
    		P=traslaz(P,T);
    		break;
    	case2 : 	
                	printf ("Centro di simmetria ?");
    		punto S=leggiPto();
    		P=simm(P,S);
    		break;
    	case3 : 	
                	printf ("Asse di simmetria ?");
                	retta asse;
    		asse=leggiRetta();
    		P=simmAss(P,asse);
    		break;
    	case4 : 	
                	printf ("Centro di rotazione ?");
    		punto C=leggiPto();
    		printf ("\nAngolo di rotazione (rad)?");
    		float ang;
    		scanf("%f",&ang);
    		P=rotaz(P,C,ang);
    		break;
    	}
    	printf("\n\nLe nuove coordinate sono x = %f e y = %f",P.x,P.y);
    }
    
    punto leggiPto(){
    	punto P;
    	printf ("x = ");  scanf("%f",&P.x);
    	printf ("y = ");  scanf("%f",&P.y);
    	return P;
    }
    
    
    punto traslaz(punto P, punto T){
            punto P1;
    	P1.x = P.x + T.x;
    	P1.y = P.y + T.y;
    	return P1;
    }
    
    punto simm(punto P, punto S){
            punto P1;
            P1.x = 2*S.x - P.x;
    	P1.y = 2*S.y - P.y;
    	return P1;
    }
    

    pagine di Roberto Ricci L.S. "A. Righi", Bologna. Ultima revisione