* * Ora parleremo dell'I/O, ossia Input/Output (Entrata/Uscita). * Il sistema I/O del C ha un'interfaccia indipendente dall'hardware, ossia * pone un certo livello di astrazione tra il programmatore e il dispositivo * in uso, per cui e' analogo accedere a terminali, unita' a disco, a nastro * eccetera. Benche' ogni dispositivo sia diverso dagli altri, vengono * trasformati dall'ANSI C in un dispositivo logico chiamato FLUSSO. * I tipi di flusso sono 2: * * 1) FLUSSO DI TESTO: e' una sequenza di caratteri, che pero' durante il * trasferimento puo' subire anche delle conversioni secondo le necessita' * dell'ambiente di destinazione (ad esempio il carattere di fine riga e' * diverso in certi casi: puo' essere di newline o cr+lf) il che implica * che il flusso eventualmente convertito puo' essere anche di dimensione * diversa. Passando un file non di testo da questo flusso si danneggia! * * 2) FLUSSO BINARIO: e' una sequenza di byte avente una corrispondenza uno * a uno con la sequenza rivevuta dal dispositivo esterno. Non avvenendo * alcuna conversione il numero di byte scritti/letti rimane uguale. * * Abbiamo gia' visto comandi per I/O da e verso la console (tastiera/video), * ossia printf/scanf, gets/puts, per leggere o scrivere stringhe e caratteri * vari. A noi interessa maggiormente la lettura/scrittura nei FILE, in * particolare su Hard Disk/Floppy, ad esempio nel caso volessimo salvare * dei dati da un nostro programma, per poi rileggerli in un secondo momento * per un nuovo utilizzo (file di preferenze settaggio, di dati ecc.). * Veniamo quindi alla pratica: per leggere un file, le operazioni sono * queste: "aprire" quel file con fopen(), leggerlo con fread(), e chiuderlo * con fclose(). Una volta aperto un file (o piu' genericamente un flusso), * otteniamo un PUNTATORE associato a quel file. * Il PUNTATORE A UN FILE e' un vero e proprio puntatore, che punta ad * informazioni sul file aperto, come il nome, lo stato e la posizione * corrente. Un puntatore di file e' una variabile puntatore di tipo FILE: * * FILE *puntailfile * * In questo modo abbiamo creato un puntatore chiamato puntailfile adatto * a contenere i dati di un file aperto con fopen in questo modo: * * puntailfile = fopen("nomefile", modalita'); * * Dove nomefile e' il nome del file, ed eventualmente il path, e "modalita'" * e' il modo di apertura desiderato (apertura di un file in lettura, oppure * creazione di un file in scrittura, ad esempio). * Ecco alcune delle modalita' piu' comuni: * * "rt" Apertura di un file di testo in lettura * "wt" Creazione di un file di testo in scrittura * "rb" Apertura di un file binario in lettura * "wb" Creazione di un file binario in scrittura * * "rt" e "rb" servono per leggere un file esistente, "wt" e "wb" invece * creano un file nuovo per scriverci qualcosa. Se esiste gia' un file * con quel nome, viene sovrascritto. Due esempi di modo di apertura: * * puntailfile = fopen("c:\file.bau", "rb"); * file binario in lett. * puntailfile = fopen("pippo.pip", "wt"); * file di testo in scritt. * * Dato che puo' verificarsi un errore nell'apertura, di solito si controlla: * * if ((puntailfile = fopen("pippo.pip", "rb"))==NULL) { * puts("\nImpossibile aprire il file.\n"); * errore = 1 } * * Questo significa: se l'apertura del file fallisce, segna nella variabile * errore il valore 1, che potra' in seguito essere controllato per sapere * che il file non e' stato aperto. Altrimenti si potrebbe usare il return() * con un valore particolare, o si fa terminare il programma. * NULL e' un alias per 0, solitamente, e si usa per controllare se il * puntatore e' rimasto NULL, ossia non inizializzato dopo l'apertura. * Una volta aperto lo stream, si puo' leggere e scrivere con fread() e * fwrite(). * * Vediamo di mettere in pratica le ultime cose dette, leggendo questo * file (clez6a.c) e facendone una copia, chiamata clez6a.bak. * Se non trova il file, aggiungete il path. * Ci serve di sapere qualche altra istruzione: fputc(), e' un putchar per * i file, come si intuisce dal nome, e ci servira' per copiare un char * alla volta da un file all'altro. Per sapere quanti char copiare, ossia * quando finisce il primo file, possiamo usare feof(). * Attenzione che si scrive su HD/FD, io vi ho avvertito! */ #include <stdio.h> /* Includiamo la libreria standard */ /* Funzione principale e inizio del programma */ int main(void) /* Funzione principale, eseguita per prima */ { /* Inizio della funzione main() */ int errore = 0; /* Variabile che uso per segnare eventuali errori */ FILE *leggoinput, *scrivooutput; /* Definisco 2 strutture FILE */ /* Provo ad aprire il file CLEZ6A.C in modalita' lettura file di testo */ if ((leggoinput = fopen("CLEZ6A.C", "rt")) == NULL) /* Se non si apre...*/ { printf("\nNon posso aprire il file di input.\n"); errore=1; /* Segna l'errore */ } if (errore==0) { /* Se non si e' verificato l'errore apro la dest. */ /* Provo ad aprire il file CLEZ6A.BAK in modalita' scrittura file di testo */ if ((scrivooutput = fopen("CLEZ6A.BAK", "wt")) == NULL) /* Si apre!? */ { printf("\nNon posso aprire il file di output.\n"); errore=2; /* Uscita con errore */ } } if (errore==0) { /* Se non si e' verificato l'errore copio */ /* Se sono riuscito ad aprire entrambi i file, posso copiare il primo nel secondo, char dopo char, fino alla fine. Per sapere quando sono arrivato alla fine, uso feof(), che ritorna 0 finche' non si raggiunge la fine del file (ossia EOF). Da notare l'operatore negazione "!". */ while (!feof(leggoinput)) /* Finche' NON siamo alla fine del file...*/ fputc(fgetc(leggoinput), scrivooutput); /* Copia 1 char alla volta */ } /* File copiato, posso chiudere i due flussi (stream), sempre che sia riuscito ad aprirli senza errori! */ if(errore!=1) fclose(leggoinput); if(errore!=2) fclose(scrivooutput); /* Scriviamo un messaggio di felicitazioni, o di rammarico per errore.*/ if(errore==0) printf("\nHo avuto successo!\n"); else printf("\nInsuccesso totale!\n"); return(0); /* la funzione main restituisce uno 0 intero */ } /* Fine della funzione main() */ /* Facile, no? * In Java troveremo differenze di sintassi, ma la logica e' molto simile, * a parte le limitazioni sulla scrittura, per motivi di sicurezza. */