I FILE Ogni volta che usiamo un programma, inseriamo dei dati in un eseguibile, quando il programma termina tutti i dati inseriti si perdono. L ideale sarebbe avere a disposizione un qualcosa che permette di conservare i dati e di ripescarli quando servono. Quel qualcosa prende il nome di FILE. Un FILE è una sequenza di elementi il cui numero può crescere indefinitamente in base alle esigenze (un file è perciò una struttura dinamica). I file servono ad un programma per trasferire o organizzare informazioni dall esterno. Tra le informazioni importanti che possiamo registrare su file, molto importanti sono quelle che rigurdano tipi di dati omogenei; un file di questo tipo è chiamato ARCHIVIO. Un ARCHIVIO è un insieme di registrazioni (o records) ciascuna delle quali è costituita di un insieme di informazioni elementari dette attributi (o campi ). Un archivio di dati è quindi un insieme di informazioni organizzate in modo che: Tra loro ci sia un nesso; siano rappresentate secondo un formato che ne renda facile la lettura o l interprestazione; siano organizzate in modo da rendere semplice l accesso e veloce il ritrovamento: siano registrate su un supporto (magnetico, ottico o di carta) dove si possono leggere o scrivere le informazioni. Esempi di archivi sono: il registro delle informazioni che si riferiscono a ciascun cliente di un azienda (Cognome, Nome, Partita Iva, Saldo), l anagrafe di un comune, il registro scolastico. L uso degli archivi di dati su supporti di memoria di massa rende disponibile per l elaborazione una quantità di dati rilevante che non potrebbe essere contenuta nella memoria centrale di un computer. Comunemente per indicare un archivio di dati si usa il termine inglese file. I dati archiviati non sono un insieme disordinato, ma hanno una struttura e formano un sistema organizzato per la conservazione e il trattamento 1
dei dati. Un file può essere considerato come un insieme di record legati fra loro da un nesso logico. E una struttura dati che realizza concretamente la struttura a tabella definita precedentemente. Per gestione di un archivio si intende la possibilità di eseguire operazioni di inserimento, modifica, cancellazione e visualizzazione di dati in file. 1 OPERAZIONI SUI FILE Apertura: consente l inizio delle operazioni sul file e permette al sistema di individuare sul supporto fisico l inizio del file. Lettura di un dato dal file; Scrittura di un dato sul file; Chiusura: segnala il termine delle operazioni sul file. L elaborazione dei file non avviene on memoria centrale (CENNI??) (a causa delle dimensioni avolte elevate del file), ma sempre un elemento (record) per volta, lavorando su un apposita area di appoggio chiamata buffer che viene riservata quando si apre il file e rilasciata durante l operazione di chiusura. Tale area è organizzata come uno degli elementi componenti il file, predisposta in memoria centrale per ricevere i dati da elaborare. L operazione di lettura trasferisce dal supporto periferico (Hard disk, floppy, pennina) alla memoria il record da trattare; è detta operazione di input. L operazione di scrittura trasferisce dalla memoria al supporto periferico (Hard disk, floppy, pennina) il record da trattare; è detta operazione di output. Con le operazioni di aprtura del file viene anche riservata un area di memoria centrale, detta buffer di I/O, usata per le operazioni di lettura e scrittura su file. L area è rilasciata durante l operazione di chiusura, con opportuni comandi per svuotare il buffer. 2 Tipi di file Esistono due tipi di file: FILE TESTO (o ASCII) FILE BINARI 2
La differenza fra i due riguarda la loro leggibilità: I FILE TESTO (o ASCII) contengono caratteri di fine riga (EOL, end of line) per fornire un ìimpaginazione delle informazioni contenute e ciascun byte rappresenta un carattere della codifica ASCII. I FILE BINARI rappresentano un flusso continuo di bit, ragguppati in byte, ma non necessariamente distinti l uno dall altro. Prima si utilizzavano prevalentemente i file di testo, in quanto un unico tipo di file gestiva sia dati per gli utenti (lettere, bolle, fatture, programmi sorgenti) che linguaggio macchina (programmi applicativi,comandi del sistema), che potevano essere letti immediatamente, erano subito comprensibili, senza un programma di scrittura. Sono visualizzati ancora oggi con Blocco note. Oggi invece esistono file personalizzati dal programma che li ha creati; per esempio i file creati da word sono leggibili e modificabili solo da word. Il C++, non essendo un linguaggio orientato al settore gestionale gestisce il file come dispositivo di I/O e non come gestione di dati. 3 Accesso agli archivi Il tipo di accesso ai file rappresenta il modo di accedere ad un informazione memorizzata nel file, cioè le modalità con cui il programma utilizza i byte contenuti nei blocchi fisici rendendoli disponibili in memoria centrale per l elaborazione, rappresentano il tipo di accesso al file. Esistono due tipi di accesso: Sequenziale Diretto In un file a struttura sequenziale gli elementi che lo compongono vengono memorizzati tenendo conto della sequenza con la quale si presentano; gli elementi possono essere ritrovati scorrendo tutti i dati, dal primo sino all ultimo. Questo tipo di accesso consente di avere record di lunghezza variabile, ma ha dei limiti nel ritrovamento dei dati, quando il numero delle componenti è elevato (ex: trovare un brano in una musicassetta). Efficace per brani di piccole dimensioni. 3
L accesso diretto si può usare con record di lunghezza fissa e aventi tutti la stessa struttura; consente di riferirsi solo alla specifica componente, identificando la sua posizione all interno del file. La maggior parte dei problemi gestionali (registro di classe, archivio clienti) ha caratteristiche consone ad un file ad accesso diretto. Questo tipo di accesso è detto pure random (asuale) per contrapporlo all organizzazione sequenziale, in quanto l utente può accedere alla componente d interesse senza leggere tutte quelle che la precedono.è conveniente negli archivi in cui i record sono identificati attraverso un numero d ordine progressivo (ex. archivio anagrafico degli studenti di una scuola) 4 Record aventi la stessa lunghezza (FILE BINARI IN C) Per manipolare i dati in C++ occorre la libreria <stdio.h>, in cui è definita la costante EOF (end of file), che vale -1, che permette di controllare quando si è arrivati alla fine del file. 4.1 Dichiarazione FILE *fp; - FILE indica un tipo di dato strutturato (record o struttura) definito nella libreria; - *fp è il nome con cui identifichiamo il file, è un puntatore al file (fp sta per File Pointer). 4
4.2 Apertura Associa il nome di un file esterno (che si trova nella memoria di massa) al nome interno (file pointer) dl file. fp = fopen ( nomefisico, modo ); - nomefisico indica il nome dato al file (ex. amici.txt); - modo è la modalità con cui aprire un file, i comandi sono nella tabella seguente e sono differenti se vogliamo usare un file di testo o un file binario. FILE FILE TESTO BINARI r rb Solo lettura (read) Se il file non esiste, restituisce un messaggio di errore w wb Solo scrittura (write) Se il file non esiste, viene creato; se esiste viene effettuata la sovrascrittura a partire dall inizio con perdita dei dati precedenti r+ r+b Lettura e scrittura w+ w+b Scrittura e Lettura a ab Scrittura in fondo al file Se il file non esiste, viene creato; (Append) se esiste viene effettuata la scrittura in coda ai dati già esistenti a+ a+b Scrittura in fondo al file e lettura Ex: fp = fopen ( amici.txt, w ); crea un file chiamato amici.txt in cui è possibile scriverci sopra. Il C non distingue tra accesso diretto o sequenziale; dipende dal programmatore organizzare l accesso in maniera differente. 4.3 Chiusura Chiude un file aperto: fclose (fp); L istruzione fclose interrompe il collegamento tra il file fisico sulla memoria di massa e il nome interno del file, liberando anche il buffer di I/O in memoria centrale. 5
4.4 Lettura Legge una componente dal file e ne trasferisce il contenuto nella memoria centrale; fread( buffer,dimensione, NumeroElementi, fp); Il primo parametro riguarda l indirizzo del buffer di memoria, la dimensione in byte di una componente del file, il numero delle componenti che vengono lette e il puntatore al file. Ex: fread( nomi,sizeof(struct agenda),1,fp); 4.5 Scrittura Scrive il contenut del buffer dalla memoria centrale sul file: fwrite( buffer,dimensione, NumeroElementi, fp); Come si può notare ha gli stessi parametri della funzione di lettura. 4.6 Fine del file Funzione che restituisce lo stato di raggiungimento della fine del file nelle opreazioni di lettura sequenziale delle componenti: il suo valore diventa VERO ( 0) quando si legge l ultima componente, è FALSO (= 0) altrimenti. feof(fp); 4.7 Posizionamento Specifica dell accesso random al file. Indiviua la posizione di una specifica componente del file calcolando il numero di byte della componente che la precedono. Precede le operazioni di lettura e scrittura sul file. fseek(fp, posizione, inizio); posizione indica il numero dei byte con i quali il puntatore al file viene spostato aventi nel file (se è negativo viene spostato indietro); inizio indica il punto di partenza per il posizionamento e precisamente: inizio = 0 posizionamento a partire dall inizio del file; inizio = 1 posizionamento a partire dalla posizione corrente del puntatore; inizio = 2 posizionamento a partire dalla fine del file; Posizione dev essere un parametro di tipo long. 6
fseek restituisce il valore 0 se il posizionamento è riuscito correttamente, diverso da 0 altrimenti. Per conoscere in ogni istante la posizione del puntatore al file (di tipo long) attraverso la funzione ftell che ha come argomento il puntatore stesso: long pos; pos = ftell(fp); 5 Esempio accesso SEQUENZIALE Scrivere un programma per archiviare e gestire i dati di un listino prezzi. Si definisce un record che contiene due campi: la descrizione di un prodotto e il suo prezzo. La fase di registrazione è di tipo sequenziale: per ogni articolo si inseriscono i dati da tastiera, tali dati costituiscono la struttura che viene poi scritta sul file. #include<stdio.h> #include<iostream.h> #include<conio.h> //dichiarazione della struttura struct merce{ char descrizione[15]; float prezzo; ; merce articolo; FILE *fp; void registra (void); void stampa (void); int main() { //registrazione fp=fopen("listino.txt","wb"); registra(); fclose(fp); //elenco degli articoli fp=fopen("listino.txt","rb"); if(fp!=null) { stampa(); 7
fclose(fp); else printf("errore: l archivio non esiste"); getch(); return 0; //inserimento degli articoli void registra(void) { int risposta; do{ printf("inserimento di un articolo \n"); printf("descrizione: "); scanf("%s", articolo.descrizione); printf("prezzo: "); scanf("%f", &articolo.prezzo); fwrite(&articolo, sizeof(merce), 1, fp); printf("eleno finito? (0=no,1=si): "); scanf("%d",&risposta); while(!risposta); return; //stampa dell elenco void stampa (void) { fprintf(stdout,"listino articoli \n"); fread(&articolo,sizeof(merce), 1, fp); return; while(!feof(fp)) { fprintf(stdout, "%-25s ",articolo.descrizione); fprintf(stdout, "%12.2f \n",articolo.prezzo); fread(&articolo,sizeof(merce), 1, fp); 8
6 Accesso DIRETTO Se le componenti del file hanno tutte la stessa struttura, per effetto di scrittura su file, ciascuna registrazione acquisisce un numero d ordine all interno dell archivio che diventa il suo codice di registrazione. Per individuare la posizione dei dati all interno dell archivio, se si indica con i il codice, il posizionamento si ottiene moltiplicando il numero delle registrazioni che la precedono per la dimensione della struttura: posizione = (i-1) * dimensione (struttura) Dopo aver calcolato la posizione è possibile effettuare un operazione di lettura o scrittura. Occorre specificare che il linguaggio usato non prevede istruzioni per rappresentare le modifiche e la cancellazione dei dati sul file. Per fare la modifica occorre sfruttare le operazioni di lettura e scrittura: posizionamento lettura dei dati dal buffer inserimento da tastiera di nuovi dati riposizionamento scrittura del buffer sul file. La cancellazione può essere realizzata con la scrittura sopra i campi della struttura di spazi bianchi o attraverso i caratteri di controllo, per esempio il carattere. 6.1 Esempio accesso DIRETTO ESERCIZIO ATLAS PAG 494 Una sostanziale differenza fra file ad accesso sequenziale e file ad accesso diretto sta nella possibilità di poter leggere, in quest ultimo, i record chw si trovano prima del puntamento corrente. Se nel sequenziale si vuole leggere il tero record dopo aver letto il quarto è necessario chiudere il file e riaprirlo. Con l accesso diretto è invece sufficente riposizionare il puntatore al file chiamato fseek.. 9
7 FILE DI RECORD A LUNGHEZZA VARI- ABILE Anche il testo di un programma o un documento registrato su memoria di massa sono considerati come file: le istruzione del programma o le righe del documento sono le componenti del file. In questo caso il file è formato da record a lunghezza variabiule, da linee di caratteri, e si chiama FILE DI TESTO: ogni record termina con un marcatore di EOL (end of line). Per tali tipi di file si utilizza in genere l accesso sequenziale in lettura e scrittura. Le modalità con cui si apre sono quelle viste precedentemente per i file a lunghezza costante. Dal punto di vista del sistema operativo, la tastiera è considerata come un file di testo dove si possono fare solo operazioni di input, il video e la stampante sono file di testo dove si possono fare solo operazioni di output. Per effettuare operazioni dei lettura e scrittura formattare si usano le istruzioni fscanf e fprintf, che hanno la seguente sintassi: fprintf(fp, "\%s \n",nome) fscanf(fp, "\%s",nome) fp è il nome del puntatore, % indica il tipo di dato da usare (s è un carattere, d un intero, f un float), nome la variabile il cui valore va inserito sul file (fprintf) o in cui inserire il valore letto dal file (fscanf). La lettera f sta a significare che stiamo utilizzando un file. 7.1 Esempio file di testo Creare l archivio degli amici. #include<stdio.h> FILE *fp; char nome[30]; void chiedinome(void); int main() { fp=fopen("amici.txt","w"); chiedinome(); while(nome[0]!= * ) { 10
fprintf(fp,"%s \n",nome); chiedinome(); fclose(fp); return 0; void chiedinome(void) { printf("dammi il nome dell amico (* per finire): "); scanf("%s",nome); return; Aggiungere i nomi delle amiche nel precedente archivio #include<stdio.h> FILE *fp; char nome[30]; void chiedinome(void); int main() { fp=fopen("amici.txt","a"); chiedinome(); while(nome[0]!= * ) { fprintf(fp,"%s \n",nome); chiedinome(); fclose(fp); return 0; void chiedinome(void) { printf("dammi il nome dell amico (* per finire): "); scanf("%s",nome); return; 11
Visualizzare il precedente archivio Nell istruzione fprintf compare la parola stdout stampa sullo schermo i risultati letti, ma con il comando stdprn è possibile mandare i dati a una stampante, se collegata. #include<stdio.h> #include<conio.h> int main() { FILE *fp,*st; char *nome[30]; fp=fopen("amici.txt","r"); fscanf(fp,"%s \n",nome); while(!feof(fp)) { fprintf(stdout,"%s \n",nome); //stdout scrive sullo schermo //il contenuto del file fscanf(fp,"%s",nome); fclose(fp); getch(); return 0; 8 Operazioni sui singoli caratteri Il linguaggio fornisce due funzioni: fgetch, per la lettura fputc, per la scrittura Per esempio: c = fgetch(fp1) assegna alla variabile c il carattere letto dal file avente come nome interno fp1. fputc(c,fp1) scrive il carattere, contenuto nella variabile c, nel file avente come nome interno fp1. 12
La prima istruzione è equivalente a scrivere: fscanf (fp1, %c, c); mentre la seconda è equivalente a fprintf(fp1, %c, c); Esempio: Scrivere il programma che permette di copiare il contenuto di un file binario in un altro file binario. #include<stdio.h> int main() { FILE *fp1,*fp2; int c; // variabile per leggere il contenuto del file //apre primo file in lettura fp1=fopen("prova1.doc","rb"); //apre secondo file in scrittura fp1=fopen("prova2.doc","wb"); c=fgetch(fp1); while(!feof(fp1)) { fputc(c, fp2); // scrive in fp2 il contenuto di c c=getch(fp1); // legge nuovo elemento da fp1 //chiusura file fclose(fp1); fclose(fp2); getch(); return 0; 13