next up previous contents index return to home!
Next: Relazioni tra libreria Posix Up: Il File System di Previous: File permission bits   Indice   Indice analitico

La I/O Standard Library

Il comitato di standardizzazione ANSI ha formalizzato uno standard per fare I/O bufferizzato che va sotto il nome di I/O Standard Libary (stdio). Esso è (o dovrebbe essere) indipendente dalla piattaforma su cui è inplementato, quindi potrete ritrovare la stessa libreria sui vari UNIX e sui sistemi Windows. Questa libreria fornisce l'accesso a delle strutture che tentano di facilitare e di ottimizzare l'I/O.

Le funzioni della standard library utilizzano tutte una struttura chiamata FILE. L'accesso a questa struttura avviene sempre tramite puntatore e utilizzando le funzioni appropriate: l'utente non dovrebbe mai accedere direttamente ai suoi campi. Un tale tipo di dati viene spesso chiamato ``tipo opaco''.

Per aprire un file si utilizza la funzione fopen():



#include<stdio.h>

FILE *fopen(const char *pathname, const char *type);


Il parametro type può essere ``r'' (se il vogliamo aprire in lettura), ``w'' (se vogliamo aprire in scrittura) o ``a'' (se vogliamo aprire in append). Se c'è un + nella stringa vuol dire che il file viene aperto in read/write. Quindi ``r+'' è equivalente a ``w+''. Possiamo anche specificare una ``b'' per significare che il file in questione è binario.

Su UNIX non c'è differenza fra file testo e file binario. Invece su DOS/Win c'è una bella differenza! Infatti, nei file testo, il carattere di ritorno carrello (CR) su UNIX viene sostituito da due caratteri su DOS/Win (CR + LF). Quindi, quando si trasferisce un file da un sistema DOS/Win a un sistema Unix e viceversa, bisogna stare attenti al tipo di file. Il flag ``b'' nei sistemi UNIX non serve a niente, ma si usa per compatibilità con i sistemi DOS.

La funzione fopen() restituisce un puntatore a una struttura FILE che può essere utilizzato nelle successive chiamate.

Tutte le funzioni della stdio realizzano un input/output bufferizzato: nella struttura FILE vi è allocato un buffer di una certa dimensione (BUFSIZ). La prima volta che il programma legge un carattere tramite una delle funzioni della stdio, in realtà viene letto un numero di caratteri pari alla dimensione del buffer: successive letture di caratteri si tradurranno in letture dal buffer. Stessa cosa avviene quando un programma scrive un carattere: per prima cosa viene scritto nel buffer: quando il buffer è effettivamente pieno (oppure in seguito ad un'operazione di flush) il suo contenuto viene effettivamente scritto sul disco.

Questo meccanismo cerca di minimizzare il numero di accessi al mezzo fisico che sono di solito lenti e costosi, cercando di leggere/scrivere i dati ``a blocchi''.

Un file può essere bufferizzato in 3 modi:

FULLY BUFFERED
: il trasferimento dati avviene di solito a blocchi della dimensione del buffer (a meno che non vengano effettuate delle esplicite operazioni di svuotamento).

LINE BUFFERED
: il trasferimento dati avviene a ``linee'', ovvero viene letta/scritta una linea di testo alla volta (la linea finisce con CR).

UNBUFFERED
: ogni trasferimento dati da/verso il buffer si traduce in un trasferimento dati da/verso il disco.

I 3 file stdin, stdout e stderr sono rispettivamente line-buffered, line-buffered e unbuffered, mentre un file normale aperto in lettura o scrittura è di solito fully buffered.

Come anticipato, è possibile forzare lo ``svuotamento'' di un buffer di un file in scrittura tramite la funzione fflush:



#include<stdio.h>

int fflush(FILE *fp);


Le seguenti funzioni servono per leggere un carattere per volta:



#include<stdio.h>

int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);


La prima e l'ultima sono in realtà delle macro (per questioni di efficienza). In caso venga raggiunta la fine del file, viene ritornata la costante EOF. In molti sistemi EOF viene definita come -1 che è anche il codice di errore. Per distinguere fra le due situazioni, si utilizzano le due funzioni feof() e ferror(), dal significato abbastanza ovvio.



#include<stdio.h>

int ferror(FILE *fp);
int feof(FILE *fp);


Le seguenti funzioni fanno l'output a carattere.



#include<stdio.h>

int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);


Ovviamente, è possibile fare I/O a linee:



#include<stdio.h>

char * fgets(char *buf, int n, FILE *fp);
char *gets(char *buf);
int fputs(const char *str, FILE *fp);
int puts(const char *str);


E infine è possibile fare I/O a blocchi:



#include<stdio.h>

size_t fread(void *buf, size_t size, size_t nobj, FILE *fp);
size_t fwrite(void *buf, size_t size, size_t nobj, FILE *fp);


Notare che l'utilizzo di una di queste funzioni non ha niente a che fare con il tipo di bufferizzazione del file. Per esempio è possibile utilizzare la funzione fgetc() con un file line-buffered e la funzione fwrite() con un file unbuffered: sarà la libreria a occuparsi di tradurre le chiamate di funzioni in eventuali trasferimenti da/verso il disco, a seconda del tipo di bufferizzazione del file.

Infine, riportiamo le funzioni per fare input/output formattato di stringhe:



#include<stdio.h>

int printf(const char * format, ...);
int fprintf(FILE *fp, const char * format, ...);
int sprintf(char *str, const char * format, ...);

int scanf(const char * format, ...);
int fscanf(FILE *fp, const char * format, ...);
int sscanf(char *str, const char * format, ...);




Subsections
next up previous contents index
Next: Relazioni tra libreria Posix Up: Il File System di Previous: File permission bits   Indice   Indice analitico
Giuseppe Lipari 2002-10-27