-\chapter{I file: l'interfaccia standard ANSI C}
+ \chapter{I file: l'interfaccia standard ANSI C}
\label{cha:files_std_interface}
Esamineremo in questo capitolo l'interfaccia standard ANSI C per i file,
scrittura sui file. Sono infatti previste ben tre diverse modalità
modalità di input/output non formattato:
\begin{enumerate}
-\item\textsl{a blocchi} in cui legge/scrive un blocco di dati alla
- volta, vedi \secref{sec:file_block_io}.
+\item\textsl{binario} in cui legge/scrive un blocco di dati alla
+ volta, vedi \secref{sec:file_binary_io}.
\item\textsl{di linea} in cui si legge/scrive una linea (terminata dal
carattere di newline \verb|\n|) alla volta, vedi
\secref{sec:file_line_io}.
volta (con la bufferizzazione gestita automaticamente dalla libreria),
vedi \secref{sec:file_char_io}.
\end{enumerate}
-e una modalità di input/output formattato.
-
-A differenza dell'interfaccia dei file descriptor il raggiungimento
-della fine del file è considerato un errore, e viene notificato come
-tale dai valori di uscita delle varie funzioni; nella maggior parte dei
-casi questo avviene con la restituzione del valore intero (di tipo
-\type{int}) \macro{EOF}\footnote{la costante deve essere negativa, le
- \acr{glibc} usano -1, altre implementazioni possono avere valori
- diversi.} definito anch'esso nell'header \func{stdlib.h}.
-
-Dato che le funzioni dell'interfaccia degli stream sono funzioni di
-libreria, esse non settano la variabile \var{errno}, che mantiene il
-valore settato dalla system call che ha riportato l'errore, ma siccome
-la condizione di end-of-file è anch'essa segnalata come errore, non
-esisterebbe alcuna possibilità di distinguerla da un errore (\var{errno}
-potrebbe essere stata settata in una altra occasione, vedi
-\secref{sec:sys_errno}).
+ed inoltre la modalità di input/output formattato.
+
+A differenza dell'interfaccia dei file descriptor il raggiungimento della fine
+del file è considerato un errore, e viene notificato come tale dai valori di
+uscita delle varie funzioni; nella maggior parte dei casi questo avviene con
+la restituzione del valore intero (di tipo \type{int}) \macro{EOF}\footnote{la
+ costante deve essere negativa, le \acr{glibc} usano -1, altre
+ implementazioni possono avere valori diversi.} definito anch'esso
+nell'header \func{stdlib.h}.
+
+Dato che le funzioni dell'interfaccia degli stream sono funzioni di libreria
+che si appoggiano a delle system call, esse non settano direttamente la
+variabile \var{errno}, che mantiene il valore settato dalla system call che ha
+riportato l'errore.
+
+Siccome la condizione di end-of-file è anch'essa segnalata come errore, nasce
+il problema di come distinguerla da un errore effettivo; basarsi solo sul
+valore di ritorno della funzione e controllare il valore di \var{errno}
+infatti non basta, dato che quest'ultimo potrebbe essere stato settato in una
+altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del
+funzionamento di \var{errno}).
Per questo motivo tutte le implementazioni delle librerie standard
mantengono per ogni stream almeno due flag all'interno dell'oggetto
flag sono settati.
\end{functions}
\noindent si tenga presente comunque che la lettura di questi flag segnala
-soltanto che si è avuto un errore, o si è raggiunta la fine del file, in
-una precedente operazione sullo stream.
+soltanto che c'è stato un errore, o che si è raggiunta la fine del file in una
+qualunque operazione sullo stream, il controllo quindi deve essere effettuato
+ogni volta che si chiama una funzione di libreria.
-Entrambi i flag (di errore e di end-of-file) possono essere cancellati
-usando la funzione \func{clearerr}, il cui prototipo è:
+Entrambi i flag (di errore e di end-of-file) possono essere cancellati usando
+la funzione \func{clearerr}, il cui prototipo è:
\begin{prototype}{stdio.h}{void clearerr( FILE *stream)}
Cancella i flag di errore ed end-of-file di \param{stream}.
\end{prototype}
così da poter rilevare una successiva ulteriore condizione di errore.
-\subsection{Input/output a blocchi}
-\label{sec:file_block_io}
+\subsection{Input/output binario}
+\label{sec:file_binary_io}
+
+La prima modalità di input/output non formattato ricalca quella della
+intefaccia dei file descriptor, e provvede semplicemente la scrittura e
+la lettura dei dati da un buffer verso un file e vicecersa. 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:
+\begin{functions}
+ \headdecl{stdio.h}
+ \funcdecl{size\_t fread(void * ptr, size\_t size,
+ size\_t nmemb, FILE * stream)}
+ \funcdecl{size\_t fwrite(const void *
+ ptr, size\_t size, size\_t nmemb, FILE * stream)}
+
+ Le funzioni rispettivamente leggono e scrivono \param{nmemb} elementi
+ di dimensione \param{size} dal buffer \param{ptr} al file \param{stream}.
+
+ 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.
+\end{functions}
+
+In genere si usano queste funzioni quando si devono leggere o scrivere
+un array o una struttura; un tipico esempio è quello in cui si salva una
+parte di un vettore con una chiamata del tipo:
+\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+int WriteVect(FILE * stream, double * vec, size_t nelem)
+{
+ int size, nread;
+ size = sizeof(*vec);
+ if ( (nread = fwrite(vec, size, nelem, stream)) != nelem) {
+ perror("Write error");
+ }
+ return nread;
+}
+\end{lstlisting}
+nel qual caso devono essere specificate dimensione e numero degli
+elementi del vettore; nel caso di una struttura invece si avrà un
+qualcosa tipo:
+\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+struct histogram {
+ int nbins;
+ double max, min;
+ double * bin;
+} histo;
+int WriteStruct(FILE * stream, struct histogram * histo, size_t nelem)
+{
+ if ( fwrite(vec, sizeof(*histo), 1, stream) !=1) {
+ perror("Write error");
+ }
+ return nread;
+}
+\end{lstlisting}
+
+
\subsection{Input/output a caratteri singoli}
\label{sec:file_char_io}
+
+
\subsection{Input/output di linea}
\label{sec:file_line_io}
necessiterà di informazioni aggiuntive rispetto al semplice puntatore allo
stream; questo può essere evitato con le due funzioni \func{\_\_freadable} e
\func{\_\_fwritable} i cui prototipi sono:
-
\begin{functions}
\headdecl{stdio\_ext.h}
\funcdecl{int \_\_freadable (FILE * stream)}
- \funcdecl{int \_\_fwritable(FILE * stream)}
+ Restituisce un valore diverso da zero se \param{stream} consente la lettura.
+
+ \funcdecl{int \_\_fwritable(FILE * stream)}
+ Restituisce un valore diverso da zero se \param{stream} consente la
+ scrittura.
\end{functions}
+Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} servono ad un
+uso ancora più specialistico, il loro prototipo è:
+\begin{functions}
+ \headdecl{stdio\_ext.h}
+ \funcdecl{int \_\_freading (FILE * stream)}
+ Restituisce un valore diverso da zero se \param{stream} è aperto in sola
+ lettura o se l'ultima operazione è stata di lettura.
+
+ \funcdecl{int \_\_fwriting(FILE * stream)}
+ Restituisce un valore diverso da zero se \param{stream} è aperto in sola
+ scrittura o se l'ultima operazione è stata di scrittura.
+\end{functions}
+
+Le due funzioni hanno lo scopo di determinare di che tipo è stata l'ultima
+operazione eseguita su uno stream aperto in lettura/scrittura; ovviamente se
+uno stream è aperto in sola lettura (o sola scrittura) la modalità dell'ultima
+operazione è sempre determinata; l'unica ambiguità è quando non sono state
+ancora eseguite operazioni, in questo caso le funzioni rispondono come se
+una operazione ci fosse comunque stata.
+
+La conoscenza dell'ultima operazione effettuata su uno stream aperto in
+lettura/scrittura è utile in quanto permette di trarre conclusioni sullo stato
+del buffer e del suo contenuto.
\subsection{Il controllo della bufferizzazione}