Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e...

36
Anno accademico 2010-2011 Anno accademico 2010-2011 1 Input e Output in C Input e Output in C

Transcript of Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e...

Page 1: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

11

Input e Output in C Input e Output in C

Page 2: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

22

SommarioSommario

• Input e outputInput e output I flussi di I/OI flussi di I/O L’uso di bufferL’uso di buffer Apertura e chiusura di fileApertura e chiusura di file Lettura e scrittura di datiLettura e scrittura di dati La selezione di un metodo di I/OLa selezione di un metodo di I/O I/O non bufferizzatoI/O non bufferizzato L’accesso diretto a fileL’accesso diretto a file

Page 3: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

33

IntroduzioneIntroduzione

• La gestione dell’I/O su file è uno degli aspetti più complessi dei linguaggi di programmazione, perché strettamente correlato con le particolari modalità di accesso a file ed alle periferiche dettate dal sistema operativo difficoltà nella progettazione di servizi di I/O portabili

• Storicamente, l’apposita libreria di runtime del C e la libreria di I/O di UNIX erano parzialmente sovrapposte: tuttavia, la libreria C tratta l’I/O bufferizzatobufferizzato, contrariamente alla libreria UNIX

• Le funzioni ANSI di I/O sono tutte bufferizzate (con possibilità di modifica della dimensione del buffer)

• Le funzioni ANSI di I/O operano inoltre una distinzione tra accesso a file in modalità binaria o testuale; in ambiente UNIX la distinzione è poco significativa poiché UNIX tratta file binari e file di testo alla stessa stregua come sequenze di byte (in altri sistemi operativi, tale distinzione è invece importante)

Page 4: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

44

I flussi di I/O I flussi di I/O 1 1

• Il linguaggio C non distingue tra periferiche e file su disco: in entrambi i casi le operazioni di I/O sono realizzate attraverso flussi flussi o streamstream di I/O associati a file o periferiche

• Un flusso di I/O è una sequenza ordinata di byte: la lettura e la scrittura di un file o di una periferica implicano la lettura/ scrittura di dati da/su un flusso

I flussi di I/O: i programmi C accedono ai dati I flussi di I/O: i programmi C accedono ai dati memorizzati in file attraverso array monodimensionali di memorizzati in file attraverso array monodimensionali di caratteri, detti flussi di I/Ocaratteri, detti flussi di I/O

FlussoFlusso FileFileSorgente CSorgente C

Page 5: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

55

I flussi di I/O I flussi di I/O 2 2

• Per eseguire l’I/O, è necessario associare un flusso ad un file o a una periferica

occorre dichiarare un puntatore alla struttura FILEFILE

• La struttura FILEFILE, definita in stdio.hstdio.h, è costituita da campi che contengono informazioni quali il nome del file, la modalità di accesso, il puntatore al prossimo carattere nel flusso

• I campi della struttura FILEFILE, istanziati all’atto dell’apertura di un flusso (o in fase di utilizzo), sono dipendenti dall’im-plementazione e differiscono per sistemi operativi diversi

Page 6: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

66

I flussi di I/O I flussi di I/O 3 3

• Le strutture FILEFILE forniscono al sistema operativo le informazioni necessarie per la gestione dei file: l’unico meccanismo di accesso ad un flusso è il puntatore alla struttura FILEFILE, detto puntatore a filepuntatore a file

• Il puntatore a file deve essere dichiarato nel programma, contiene l’identificatore del flusso restituito da una chiamata alla fopen()fopen(), e viene utilizzato per leggere, scrivere e chiudere il flusso

• Ciascun programma può aprire più flussi simultaneamente, nel rispetto dei limiti imposti dalla particolare implemen-tazione

Page 7: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

77

I flussi di I/O I flussi di I/O 4 4

• Uno dei campi della struttura FILEFILE è un indicatore di indicatore di posizione nel fileposizione nel file, che punta al successivo byte da leggere o scrivere: a fronte di operazioni di lettura/scrittura, il sistema operativo modifica conseguentemente l’indicatore di posizione

• L’indicatore di posizione del file non può essere manipolato direttamente (in maniera portabile), ma può essere letto e modificato tramite funzioni di libreria, permettendo accessi al flusso non sequenziali

• Attenzione:Attenzione: il puntatore a file identifica un flusso aperto, che è connesso ad un file o a una periferica, l’indicatore di posizione nel file identifica uno specifico byte all’interno di un flusso

Page 8: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

88

I flussi standardI flussi standard

• Esistono tre flussi standardflussi standard, che vengono aperti automati-camente per ogni programma: stdinstdin, stdoutstdout, stderrstderr

• I flussi standard sono connessi al terminale, per default, ma molti sistemi operativi ne permettono la redirezione (ad es., è possibile inviare messaggi di errore ad un file per effettuare diagnostica)

• Le funzioni printf()printf() e scanf()scanf() utilizzano i flussi standard di I/O; possono essere utilizzate anche per fare I/O su/da file, ridirigendo stdinstdin e stdoutstdout a file per mezzo della funzione freopen()freopen()

• Tuttavia, esistono le funzioni di libreria apposite, fprintf()fprintf() e fscanf()fscanf(), che permettono di specificare il flusso su cui operare

Page 9: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

99

I formati testo e binarioI formati testo e binario

• I dati possono essere acceduti in modalità testomodalità testo o binariabinaria:

Un flusso testualeflusso testuale è composto da una sequenza di linee, concluse da newline (sistemi operativi diversi possono memorizzare linee con formati diversi, utilizzando un carattere differente di terminazione linea)

I flussi standardflussi standard sono testuali

In formato binarioformato binario il compilatore non effettua alcuna interpre-tazione dei byte: i bit sono letti e scritti come un flusso continuo

I flussi binari sono utilizzati quando è fondamentale preservare l’esatto contenuto del file

Page 10: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1010

L’uso del buffer L’uso del buffer 1 1

• Confrontate con la memoria centrale, le unità di memoria di massa sono estremamente lente: nei programmi, il tempo richiesto per accedere alle periferiche eccede largamente il tempo impiegato dalla CPU per i calcoli

• È di fondamentale importanza ridurre il numero di operazioni di lettura/scrittura, mediante tecniche di bufferizzazionebufferizzazione

• Un bufferbuffer è un’area di memoria in cui i dati sono memorizzati temporaneamente, prima di essere inviati a destinazione

• Mediante l’uso di buffer, il sistema operativo può limitare il numero di accessi effettivi alla memoria di massa

• Tutti i sistemi operativi utilizzano buffer per leggere/scrivere su unità di I/O: l’accesso a disco, per esempio, avviene con “granularità di blocco”, con blocchi di dimensione 512/4096 byte

Page 11: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1111

L’uso del buffer L’uso del buffer 2 2

• Le librerie di runtime del C contengono un ulteriore livello di bufferizzazione che può assumere due forme distinte: bufferizzazione a lineebufferizzazione a linee e bufferizzazione a blocchibufferizzazione a blocchi Nella bufferizzazione a linee, il sistema immagazzina i

caratteri fino a quando si incontra un newline (o il buffer è pieno), inviando l’intera linea al sistema operativo (ciò che accade per l’inserimento da tastiera)

Nella bufferizzazione a blocchi, il sistema immagazzina i caratteri fino a riempire un blocco, trasferendolo quindi al sistema operativo

• Tutti i flussi di I/O a file utilizzano una bufferizzazione a bloc-chi, i flussi riferiti a terminale sono dipendenti dal sistema operativo, ma sono o non bufferizzati o bufferizzati a linee

Page 12: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1212

L’uso del buffer L’uso del buffer 3 3

• Le librerie standard di I/O del C comprendono un gestore gestore di bufferdi buffer che mantiene il buffer in memoria il più a lungo possibile: se si accede alla stessa porzione di un flusso più volte, si ha alta probabilità che il flusso sia stato mantenuto nella memoria centrale (si possono verificare problemi di accesso concorrente, gestibili via sistema operativo, se il file è condiviso da più processi)

• Sia nel caso di bufferizzazione a righe che a blocchi, è possibile richiedere esplicitamente al sistema operativo di forzare l’invio del buffer a destinazione in un momento qualsiasi, per mezzo della funzione fflush()fflush()

• Il C consente di personalizzare il meccanismo di bufferizzazione (modificando le dimensioni del buffer) fino ad eliminarla, ponendo la dimensione del buffer a zero

Page 13: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1313

Il file header Il file header stdio.hstdio.h

• Per utilizzare le funzioni di I/O è necessario includere il file header stdio.hstdio.h che contiene: Le dichiarazioni dei prototipi di tutte le funzioni di I/O

La dichiarazione della struttura FILEFILE

Le macro costanti, come stdinstdin, stdoutstdout, stderrstderr, EOFEOF

• EOFEOF corrisponde al valore restituito dalle funzioni di I/O in corrispondenza dell’identificatore di fine file

• Nota:Nota: La definizione di NULLNULL, per l’ANSI C, è invece contenuta nel file stddef.hstddef.h

#ifndef NULL

#define NULL (void *) 0

#endif

Page 14: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1414

La gestione degli erroriLa gestione degli errori

• Ogni funzione di I/O restituisce un valore speciale in caso di errore: alcune restituiscono zero, altre un valore diverso da zero o EOFEOF

• Per ogni flusso aperto, esistono due campi booleani nella struttura FILEFILE che registrano condizioni di errore o di fine file

• Si può accedere ai campi di fine file e di errore utilizzando le funzioni feof()feof() e ferror()ferror()

• La funzione clearerr()clearerr() pone entrambi i campi a zero

include <stdio.h>define ERR_FLAG 1define EOF_FLAG 2

char stream_stat(fp)FILE *fp;{/* se nessun campo booleano è alterato, * stat vale 0; se il solo campo di errore * è alterato, stat vale 1; se il solo * campo di fine file è alterato, stat * vale 2; se sono alterati entrambi, stat * vale 3 */ char stat = 0;

if (ferror(fp)) stat |= ERR_FLAG; if (feof(fp)) stat |= EOF_FLAG; clearerr(fp); return stat;}

Page 15: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1515

Apertura e chiusura di file Apertura e chiusura di file 1 1

• Prima di poter accedere al contenuto di un file, è necessario aprirlo tramite la funzione fopen()fopen(), che prevede due parametri: il nome del file e la modalità di accesso

• Esistono due insiemi di modalità di accesso, per i flussi testuali e per i flussi binari

“rr” Apre un file testuale esistente in lettura, posizionandosi all’inizio del file; se il file non esiste, la funzione ritornerà il codice di errore NULL

“ww” Crea un nuovo file testuale e lo apre in scrittura, posizionandosi all’inizio del file; se il file esiste, i dati precedenti vengono eliminati

“aa” Apre un file testuale esistente in modalità appendappend ; la scrittura può avvenire solo alla fine del file; se il file non esiste verrà creato automaticamente, in caso contrario il contenuto del file preesistente verrà mantenuto

“rr” Apre un file testuale esistente in lettura e scrittura, posizionandosi all’inizio del file; se il file non esiste, la funzione ritornerà il codice di errore NULL

“ww” Crea un nuovo file testuale e lo apre in lettura e scrittura

“aa” Apre un file testuale esistente o ne apre uno nuovo in modalità append; la lettura può avvenire in una posizione qualsiasi del file, la scrittura solo alla fine

Page 16: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1616

Apertura e chiusura di file Apertura e chiusura di file 2 2

• Le modalità binarie differiscono per l’aggiunta di una bb (es., rbrb)

• La funzione fopen()fopen() restituisce un puntatore a file, utilizzabile per accedere successivamente al file aperto

Proprietà di file e flussi rispetto alle modalità di apertura della Proprietà di file e flussi rispetto alle modalità di apertura della fopen()fopen()

rr ww aa rr ww aa

Il file deve esistere prima dell’apertura

* *

Il file preesistente viene reinizializzato

* *

Possibilità di lettura del flusso * * * *

Possibilità di scrittura sul flusso * * * * *

Possibilità di scrittura solo alla fine

* *

Page 17: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1717

Apertura e chiusura di file Apertura e chiusura di file 3 3

• Esempio:Esempio: Funzione che apre un file testuale, denominato testtest, con accesso in lettura

• Note:Note: La funzione fprintf()fprintf() è analoga alla printf()printf(),

eccettuato un parametro aggiuntivo, che identifica il flusso di uscita

La funzione open_test()open_test() è poco flessibile, perché permette l’apertura del solo file testtest e soltanto per accessi in lettura

include <stdio.h>include <stddef.h>

FILE *open_test(){/* restituisce un puntatore ad una struttura FILE */ FILE *fp;

fp fopen(“test”, “r”); if (fp NULL) fprintf(stderr,“Errore nell’apertura del file test\n”); return fp;}

Page 18: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1818

Apertura e chiusura di file Apertura e chiusura di file 4 4

include <stdio.h>include <stddef.h>

FILE *open_file(file_name, access_mode)char *file_name, *access_mode;{ FILE *fp;

if ((fp fopen(file_name, access_mode)) NULL) fprintf(stderr, “Errore nell’apertura del file %s \ con modalità di accesso %s\n”, file_name, access_mode); return fp;}

• La funzione open_file()open_file() è equivalente alla fopen()fopen(), a meno della notifica esplicita di errore se il file non può essere aperto

Page 19: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

1919

Apertura e chiusura di file Apertura e chiusura di file 5 5

• Per chiudere un file viene utilizzata la funzione fclose()fclose(), con argomento il puntatore alla struttura FILEFILE da chiudere

• La chiusura del file provoca il rilascio della struttura FILEFILE, per la successiva allocazione ad altri file

• La chiusura del file forza anche la scrittura del contenuto del buffer associato al flusso

• Dato che tutti i sistemi operativi stabiliscono un numero massimo di flussi aperti contemporaneamente, è buona norma chiudere i file quando se ne è conclusa l’elaborazione

• Tutti i flussi aperti vengono comunque chiusi dal sistema operativo quando il programma termina correttamente (nel caso di terminazione anomala, il comportamento non è standardizzato)

Page 20: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2020

Lettura e scrittura di datiLettura e scrittura di dati• Su un file aperto è possibile utilizzare il puntatore a file

per svolgere operazioni di letturalettura e scritturascrittura• Le operazioni di accesso al file possono essere

effettuate su oggetti di granularitàgranularità diversa, in particolare a livello di… …carattere …linea …blocco

• Qualsiasi sia la granularità, è impossibile leggere da un flusso e quindi scrivere sullo stesso flusso senza che fra le due operazioni venga effettuata una chiamata a fseek()fseek(), rewind()rewind() o fflush()fflush()

• Le funzioni fseek()fseek(), rewind()rewind() e fflush()fflush() sono le uniche funzioni di I/O che forzano la scrittura del buffer sul flusso

Page 21: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2121

Lettura e scrittura per caratteri Lettura e scrittura per caratteri 11

• Esistono due modalità per la lettura/scrittura di caratteri da un flusso getc()getc() : macro che legge un carattere da un flusso fgetc()fgetc() : analoga a getc()getc(), ma realizzata come una

funzione putc()putc() : macro che scrive un carattere su un flusso fputc()fputc() : analoga a putc()putc(), ma realizzata come una

funzione• Le macro getc()getc() e putc()putc(), in quanto tali, sono

normalmente molto più veloci delle analoghe funzioni• Tuttavia, se un parametro attuale contiene operatori

che implicano effetti collaterali, fgetc()fgetc() ed fputc()fputc() sono preferibili

• Per le altre macro di libreria, lo standard ANSI prevede che gli argomenti possano comparire una sola volta nel corpo della macro, per evitare (il sommarsi degli) effetti collaterali

Page 22: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2222

Lettura e scrittura per caratteri Lettura e scrittura per caratteri 22

• Esempio:Esempio: Funzione che copia il contenuto di un file in un altro

• Note:Note: Entrambi i file vengono

acceduti in modalità binaria La macro getc()getc() legge il

prossimo carattere dal flusso specificato e sposta l’indicatore di posizione del file avanti di un elemento ad ogni chiamata

In modalità binaria, non è possibile interpretare il valore di ritorno della getc()getc() per de-cretare la fine del file: feof()feof() invece non presenta ambiguità

include <stdio.h>include <stddef.h>define FAIL 0define SUCCESS 1

int copy_file(infile, outfile) char *infile, *outfile;

{ FILE *fp1, *fp2; if ((fp1 fopen(infile, “rb”)) NULL) return FAIL; if ((fp2 fopen(outfile, “wb”)) NULL) { fclose(fp1); return FAIL; } while (!feof(fp1)) putc(getc(fp1), fp2); fclose(fp1); fclose(fp2); return SUCCESS;}

Page 23: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2323

Lettura e scrittura per linee Lettura e scrittura per linee 1 1

• Esistono due funzioni di I/O orientate alle linee, fgets()fgets() ed fputs()fputs()

• Il prototipo per la funzione fgets()fgets() è char *fgets(char *s, int n, FILE *stream); char *fgets(char *s, int n, FILE *stream);

Gli argomenti hanno il seguente significato: ss : puntatore al primo elemento dell’array in cui

vengono memorizzati i caratteri letti

nn : numero massimo dei caratteri da leggere streamstream : puntatore al flusso da cui leggere

• La funzione fgets()fgets() legge caratteri fino ad un newline, la fine del file o il numero massimo specificato di caratteri, inserendo automaticamente un carattere \0\0 dopo l’ultimo carattere scritto nell’array; restituisce NULLNULL se incontra la fine del file, altrimenti restituisce il primo argomento

Page 24: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2424

Lettura e scrittura per linee Lettura e scrittura per linee 2 2

• La funzione fputs()fputs() scrive l’array identificato dal primo argomento nel flusso identificato dal secondo argomento

• La differenza fondamentale fra gets()gets() (che legge da stdinstdin) ed fgets()fgets() è che la seconda inserisce nell’array (prima del \0\0 finale) anche il carattere di newline che delimita la linea

• Inoltre fgets()fgets() permette la specifica del numero massimo dei caratteri da leggere, mentre gets()gets() procede sempre fino ad un terminatore (newline o EOFEOF)

Page 25: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2525

Lettura e scrittura per linee Lettura e scrittura per linee 3 3● Note:Note:

Il file è aperto in modalità testua-le per accedere ai dati a livello di linea, altrimenti fgets()fgets() potreb-be operare in modo scorretto, cercando caratteri di newline non presenti nel file (il terminatore di linea può essere diverso per si-stemi operativi diversi)

fgets()fgets(), invece, si “adegua” alle caratteristiche del sistema opera-tivo specifico

La funzione copy_file()copy_file() per li-nee è più lenta della versione per caratteri, poiché fgets()fgets() ed fputs()fputs() sono realizzate per mezzo di fgetc()fgetc() ed fputc()fputc() (meno efficienti delle analoghe macro)

include <stdio.h>include <stddef.h>define FAIL 0define SUCCESS 1define LINESIZE 100int copy_file(infile, outfile) char *infile, *outfile;

{ FILE *fp1, *fp2; char line[LINESIZE];

if ((fp1 fopen(infile, “r”)) NULL) return FAIL; if ((fp2 fopen(outfile, “w”)) NULL) { fclose(fp1); return FAIL; } while (fgets(line,LINESIZE1,fp1) ! NULL) fputs(line, fp2); fclose(fp1); fclose(fp2); return SUCCESS;}

Page 26: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2626

Lettura e scrittura per blocchi Lettura e scrittura per blocchi 1 1

• Un bloccoblocco può essere immaginato come un array: quando si legge o si scrive un blocco è necessario specificare il numero di elementi del blocco e la dimensione di ognuno di essi

• Le due funzioni orientate alla gestione dei blocchi sono fread()fread() e fwrite()fwrite()

• Il prototipo per la funzione fread()fread() èint fread(void *ptr,int size,int nmemb,FILE *stream); int fread(void *ptr,int size,int nmemb,FILE *stream);

• Gli argomenti hanno il seguente significato:

ptrptr : puntatore ad un array in cui vengono memorizzati i dati

sizesize : dimensione di ogni elemento dell’array nmembnmemb : numero di elementi da leggere streamstream: puntatore a file

Page 27: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2727

Lettura e scrittura per blocchi Lettura e scrittura per blocchi 2 2

• La funzione fread()fread() restituisce il numero di elementi effettivamente letti, che dovrebbe coincidere con il terzo argomento, a meno di errori o di condizioni di fine file

• La funzione fwrite()fwrite() ha gli stessi argomenti, ma scrive nel flusso gli elementi contenuti nell’array

• La funzione copy_file()copy_file() può essere realizzata anche con granularità di blocco: La condizione di fine file è controllata confrontando il

numero degli elementi letti, restituito da fread()fread(), con il valore specificato nella lista degli argomenti: se sono diversi si ha una condizione di fine file o di errore

La funzione ferror()ferror() viene utilizzata per stabilire quale condizione si è verificata

Page 28: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2828

Lettura e scrittura per blocchi Lettura e scrittura per blocchi 3 3 while ((num_readfread(block,sizeof(DATA), BLOCKSIZE,fp1)) BLOCKSIZE) fwrite(block,sizeof(DATA),num_read,fp2);

fwrite(block,sizeof(DATA),num_read,fp2);

if (ferror(fp1)) { printf(“Errore in lettura del \ file %s\n”,infile); fclose(fp1); fclose(fp2); return FAIL; } fclose(fp1); fclose(fp2); return SUCCESS;}

include <stdio.h>include <stddef.h>define FAIL 0define SUCCESS 1define BLOCKSIZE 512typedef char DATA;

int copy_file(infile, outfile) char *infile, *outfile;

{ FILE *fp1, *fp2; DATA block[BLOCKSIZE]; int num_read;

if ((fp1 fopen(infile, “rb”)) NULL) { printf(“Errore nell’apertura del file %s \ in input\n”, infile); return FAIL; } if ((fp2 fopen(outfile, “wb”)) NULL) { printf(“Errore nell’apertura del file %s \ in output\n”, outfile); fclose(fp1); return FAIL; }

Page 29: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

2929

La selezione di un metodo di I/O La selezione di un metodo di I/O 1 1

• Le macro putc()putc() e getc()getc() sono le più veloci, ma la maggior parte dei sistemi operativi è in grado di realizzare operazioni di I/O su blocchi ancora più efficienti (ad es., read()read() e write()write() in UNIX)

• Talvolta occorre privilegiare la semplicità all’efficienza: fgets()fgets() e fputs()fputs(), ad esempio, sono lente, ma particolarmente adatte nei casi in cui sia necessario analizzare linee

Funzione che conta il numero di linee di un file

include <stdio.h>include <stddef.h>define MAX_LINE_SIZE 120

int lines_in_file(fp)FILE *fp;{ char buf[MAX_LINE_SIZE]; int line_num 0;

rewind(fp); /* sposta l’indicatore di posizione all’inizio del file */

while (fgets(buf,MAX_LINE_SIZE,fp)! NULL) line_num; return line_num;}

Page 30: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3030

La selezione di un metodo di I/O La selezione di un metodo di I/O 2 2

• Ultimo, ma non meno importante, fattore da considerare nella scelta di un metodo di I/O è la portabilità, fondamen-tale non tanto nella scelta del tipo di I/O (granularità a caratteri, linee o blocchi), ma nella scelta della modalità testo o binaria

Se il file contiene dati testuali (codice sorgente o documenti), la modalità testo e l’accesso per linee sono da privilegiare

Se i dati sono numerici e non sono strutturati per linee, è preferibile la modalità binaria, con accesso per caratteri o per blocchi (codice eseguibile)

Page 31: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3131

I/O non bufferizzato I/O non bufferizzato 1 1

• Le librerie di runtime del C consentono di modificare la dimensione del buffer: tale possibilità deve essere utilizzata con attenzione, dato che la dimensione del buffer dovrebbe essere “ottima” per il particolare sistema operativo

• Talvolta, è tuttavia necessario eliminare completamente la bufferizzazione, tipicamente quando si vogliono elaborare immediatamente i dati di input

• Per eliminare la bufferizzazione ci si può avvalere delle funzioni setbuf()setbuf() e setvbuf()setvbuf()

• La funzione setbuf()setbuf() richiede due parametri: un puntatore a file, ed un puntatore ad un array di caratteri da utilizzare come nuovo buffer; se tale puntatore è nullo, la bufferizzazione viene eliminata; setbuf()setbuf() non restituisce valori

setbuf(stdin,NULL);

Page 32: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3232

I/O non bufferizzato I/O non bufferizzato 2 2

• La funzione setvbuf()setvbuf() richiede due parametri aggiuntivi, che permettono di specificare la tipologia di bufferizzazione (per linee, per blocchi, o assente) e la dimensione dell’array da utilizzare come buffer

• La tipologia di bufferizzazione va specificata mediante uno dei tre simboli definiti in stdio.hstdio.h: _IOFBF_IOFBF : bufferizzazione per blocchi _IOLBF_IOLBF : bufferizzazione per linee _IONBF_IONBF : bufferizzazione assente

• La funzione restituisce un valore diverso da zero se completata correttamente, zero se non è in grado di soddisfare la richiesta

setvbuf(stdin,NULL,_IONBF,0);

Page 33: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3333

L’accesso diretto a file L’accesso diretto a file 1 1

• In C, le funzioni per l’accesso diretto a file sono fseek()fseek() e ftell()ftell()

• La funzione fseek()fseek() sposta l’indicatore di posizione del file a un carattere specificato nel flusso

• Il prototipo della fseek()fseek() è int fseek(FILE *stream,long int offset,int whence) int fseek(FILE *stream,long int offset,int whence)

dove: streamstream : puntatore a file offsetoffset : numero di caratteri di spostamento whencewhence : posizione di partenza da cui calcolare lo spostamento

• L’argomento whencewhence può assumere uno dei tre seguenti valori, definiti in stdio.hstdio.h SEEK_SETSEEK_SET : inizio del file SEEK_CURSEEK_CUR : posizione corrente dell’indicatore SEEK_ENDSEEK_END : fine del file

Page 34: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3434

L’accesso diretto a file L’accesso diretto a file 2 2

• Esempio:Esempio: L’istruzionestat stat fseek(fp,10,SEEK_SET); fseek(fp,10,SEEK_SET);

sposta l’indicatore di posizione del file al carattere 10 del flusso (l’undicesimo), che sarà il prossimo elemento letto o scritto

• La fseek()fseek() restituisce zero se la richiesta è corretta, un valore diverso da zero altrimenti

• Esempio:Esempio: L’istruzionestat stat fseek(fp,1,SEEK_END); fseek(fp,1,SEEK_END);

non è lecita se fpfp è aperto in sola lettura, perché sposta l’indicatore oltre la fine del file

• Per flussi binari, lo spostamento può essere un qualsiasi numero intero che non sposti l’indicatore al di fuori del file; per flussi testuali, deve essere zero o un valore restituito dalla ftell()ftell()

Page 35: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3535

L’accesso diretto a file L’accesso diretto a file 3 3

• La funzione ftell()ftell() richiede, come unico argomento, un puntatore a file e restituisce la posizione corrente dell’indi-catore di posizione nel file

• La posizione restituita da ftell()ftell() si intende relativa all’inizio del file… …per flussi binari rappresenta il numero di caratteri

dall’inizio del file alla posizione corrente …per flussi testuali rappresenta un valore dipendente

dall’implementazione, significativo solo se utilizzato come parametro per la fseek()fseek()

cur_pos ftell(fp);if (search(string) FAIL) fseek(fp,cur_pos,SEEK_set);

Se la ricerca di una certa stringa nel file fallisce, l’indicatore di posizione nel file viene riportato al valore originale

Page 36: Anno accademico 2010-2011 1 Input e Output in C. Anno accademico 2010-2011 2 Sommario Input e outputInput e output I flussi di I/O I flussi di I/O Luso.

Anno accademico 2010-2011Anno accademico 2010-2011

3636

Esempio: dimensione del fileEsempio: dimensione del file

/* Determinazione del numero di caratteri di un file con fseek e ftell */include <stdio.h>main(int argc, char **argv) { FILE *fp; long n;

if (argc<2) printf(“File non specificato\n”); else { fpfopen(argv[1], “rb”); /* apertura del file */ if (fp ! NULL) { fseek(fp, 0, SEEK_END); /* puntatore alla fine del file */ nftell(fp); /* lettura posizione del puntatore */ fclose(fp); printf(“Dimensione del file %ld\n”, n); } else printf(“Errore: il file %s non esiste”, argv[1]); }}