[Avanti]  [Indietro]  [Su]  

7.2.3 Input/output binario

La prima modalità di input/output non formattato ricalca quella della interfaccia dei file descriptor, e provvede semplicemente la scrittura e la lettura dei dati da un buffer verso un file e viceversa. In generale questa è la modalità che si usa quando si ha a che fare con dati non formattati. Le due funzioni che si usano per l'I/O binario sono fread ed fwrite; i loro prototipi sono:

Entrambe le funzioni ritornano il numero di elementi letti o scritti, in caso di errore o fine del file viene restituito un numero di elementi inferiore al richiesto.

In genere si usano queste funzioni quando si devono trasferire su file blocchi di dati binari in maniera compatta e veloce; un primo caso di uso tipico è quello in cui si salva un vettore (o un certo numero dei suoi elementi) con una chiamata del tipo:

1: int WriteVect(FILE *stream, double *vec, size_t nelem)  
2: { 
3:     int size, nread; 
4:     size = sizeof(*vec); 
5:     if ( (nread = fwrite(vec, size, nelem, stream)) != nelem) { 
6:         perror("Write error"); 
7:     } 
8:     return nread; 
9: } 
in questo caso devono essere specificate le dimensioni di ciascun elemento ed il numero di quelli che si vogliono scrivere. Un secondo caso è invece quello in cui si vuole trasferire su file una struttura; si avrà allora una chiamata tipo:
01: struct histogram { 
02:     int nbins;  
03:     double max, min; 
04:     double *bin; 
05: } histo;  
06:  
07: int WriteStruct(FILE *stream, struct histogram *histo)  
08: { 
09:     if ( fwrite(histo, sizeof(*histo), 1, stream) !=1) { 
10:         perror("Write error"); 
11:     } 
12:     return nread; 
13: } 
in cui si specifica la dimensione dell'intera struttura ed un solo elemento.

In realtà quello che conta nel trasferimento dei dati sono le dimensioni totali, che sono sempre pari al prodotto size * nelem; la sola differenza è che le funzioni non ritornano il numero di byte scritti, ma il numero di elementi.

La funzione fread legge sempre un numero intero di elementi, se incontra la fine del file l'oggetto letto parzialmente viene scartato (lo stesso avviene in caso di errore). In questo caso la posizione dello stream viene impostata alla fine del file (e non a quella corrispondente alla quantità di dati letti).

In caso di errore (o fine del file per fread) entrambe le funzioni restituiscono il numero di oggetti effettivamente letti o scritti, che sarà inferiore a quello richiesto. Contrariamente a quanto avviene per i file descriptor, questo segnala una condizione di errore e occorrerà usare feof e ferror per stabilire la natura del problema.

Benché queste funzioni assicurino la massima efficienza per il salvataggio dei dati, i dati memorizzati attraverso di esse presentano lo svantaggio di dipendere strettamente dalla piattaforma di sviluppo usata ed in genere possono essere riletti senza problemi solo dallo stesso programma che li ha prodotti.

Infatti diversi compilatori possono eseguire ottimizzazioni diverse delle strutture dati e alcuni compilatori (come il gcc) possono anche scegliere se ottimizzare l'occupazione di spazio, impacchettando più strettamente i dati, o la velocità inserendo opportuni padding per l'allineamento dei medesimi generando quindi output binari diversi. Inoltre altre incompatibilità si possono presentare quando entrano in gioco differenze di architettura hardware, come la dimensione del bus o la modalità di ordinamento dei bit o il formato delle variabili in floating point.

Per questo motivo quando si usa l'input/output binario occorre sempre prendere le opportune precauzioni (in genere usare un formato di più alto livello che permetta di recuperare l'informazione completa), per assicurarsi che versioni diverse del programma siano in grado di rileggere i dati tenendo conto delle eventuali differenze.

Le glibc definiscono altre due funzioni per l'I/O binario, fread_unlocked e fwrite_unlocked che evitano il lock implicito dello stream, usato per dalla librerie per la gestione delle applicazioni multi-thread (si veda sez. 7.3.3 per i dettagli), i loro prototipi sono:

Le funzioni sono identiche alle analoghe fread e fwrite ma non acquisiscono il lock implicito sullo stream.

entrambe le funzioni sono estensioni GNU previste solo dalle glibc.


[Avanti]  [Indietro]  [Su]  
© 2000-2003 Simone Piccardi
Pubblicazione web curata da Mirko Maischberger