Si prosegue con l'I/O binario
authorSimone Piccardi <piccardi@gnulinux.it>
Thu, 6 Dec 2001 22:33:36 +0000 (22:33 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Thu, 6 Dec 2001 22:33:36 +0000 (22:33 +0000)
filestd.tex

index 2a22545a15e690ba79c4eeeefedda7601eb4c78e..a20d207aea09d97e4b69dfb9fd73ef0715b80d83 100644 (file)
@@ -83,81 +83,87 @@ file \file{stdio.h}.
 \subsection{Gli stream standard}
 \label{sec:file_std_stream}
 
 \subsection{Gli stream standard}
 \label{sec:file_std_stream}
 
-Ai tre file descriptor standard (vedi \secref{sec:file_std_descr}) aperti per
-ogni processo, corrispondono altrettanti stream, che rappresentano i canali
-standard di input/output prestabiliti; anche questi tre stream sono
-identificabili attraverso dei nomi simbolici definiti nell'header
-\file{stdio.h} che sono:
+Ai tre file descriptor standard (vedi \secref{sec:file_std_descr})
+aperti per ogni processo, corrispondono altrettanti stream, che
+rappresentano i canali standard di input/output prestabiliti; anche
+questi tre stream sono identificabili attraverso dei nomi simbolici
+definiti nell'header \file{stdio.h} che sono:
 
 \begin{itemize}
 
 \begin{itemize}
-\item \var{FILE * stdin} Lo \textit{standard input} cioè lo stream da cui
-  il processo riceve ordinariamente i dati in ingresso. Normalmente è associato
-  dalla shell all'input del terminale e prende i caratteri dalla tastiera.
-\item \var{FILE * stdout} Lo \textit{standard input} cioè lo stream su cui
-  il processo invia ordinariamente i dati in uscita. Normalmente è associato
-  dalla shell all'output del terminale e scrive sullo schermo.
-\item \var{FILE * stderr} Lo \textit{standard input} cioè lo stream su cui
-  il processo è supposto inviare i messaggi di errore. Normalmente anch'esso
-  è associato dalla shell all'output del terminale e scrive sullo schermo.
+\item \var{FILE * stdin} Lo \textit{standard input} cioè lo stream da
+  cui il processo riceve ordinariamente i dati in ingresso. Normalmente
+  è associato dalla shell all'input del terminale e prende i caratteri
+  dalla tastiera.
+\item \var{FILE * stdout} Lo \textit{standard input} cioè lo stream su
+  cui il processo invia ordinariamente i dati in uscita. Normalmente è
+  associato dalla shell all'output del terminale e scrive sullo schermo.
+\item \var{FILE * stderr} Lo \textit{standard input} cioè lo stream su
+  cui il processo è supposto inviare i messaggi di errore. Normalmente
+  anch'esso è associato dalla shell all'output del terminale e scrive
+  sullo schermo.
 \end{itemize}
 
 \end{itemize}
 
-Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono effettivamente
-tre variabili di tipo \type{FILE *} che possono essere usate come tutte le
-altre, ad esempio si può effettuare una redirezione dell'output di un
-programma con il semplice codice:
+Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono
+effettivamente tre variabili di tipo \type{FILE *} che possono essere
+usate come tutte le altre, ad esempio si può effettuare una redirezione
+dell'output di un programma con il semplice codice:
 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
     fclose (stdout);
     stdout = fopen ("standard-output-file", "w");
 \end{lstlisting}
 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
     fclose (stdout);
     stdout = fopen ("standard-output-file", "w");
 \end{lstlisting}
-ma in altri sistemi possono essere definite come macro, se si hanno problemi
-di portabilità e si vuole essere sicuri, diventa opportuno usare la funzione
-\func{freopen}.
+ma in altri sistemi possono essere definite come macro, se si hanno
+problemi di portabilità e si vuole essere sicuri, diventa opportuno
+usare la funzione \func{freopen}.
 
 
 \subsection{Le modalità di bufferizzazione}
 \label{sec:file_buffering}
 
 
 
 \subsection{Le modalità di bufferizzazione}
 \label{sec:file_buffering}
 
-La bufferizzazione è una delle caratteristiche principali della interfaccia
-degli stream; lo scopo è quello di ridurre al minimo il numero di system call
-(\func{read} o \func{write}) eseguite nelle operazioni di input/output. Questa
-funzionalità è assicurata automaticamente dalla libreria, ma costituisce anche
-una degli aspetti più comunemente fraintesi, in particolare per quello che
-riguarda l'aspetto della scrittura dei dati sul file.
-
-I caratteri che vengono scritti su uno stream normalmente vengono accumulati
-in un buffer e poi trasmessi in blocco in maniera asincrona rispetto alla
-scrittura (quello che viene chiamato lo \textsl{scarico}, dall'inglese 
-\textit{flush}, dei dati) tutte le volte che il buffer viene riempito. Un
-comportamento analogo avviene anche in lettura (cioè dal file viene letto un
-blocco di dati, anche se se ne sono richiesti una quantità inferiore), ma la
-cosa ovviamente ha rilevanza inferiore, dato che i dati letti sono sempre gli
-stessi; in caso di scrittura invece, quando si ha un accesso contemporaneo
-allo stesso file (ad esempio da parte di un altro processo) si potranno vedere
-solo le parti effettivamente scritte, e non quelle ancora presenti nel buffer.
-
-Allo stesso modo, se si sta facendo dell'input/output interattivo bisognerà
-tenere presente le caratteristiche delle operazioni di scarico dei dati,
-poiché non è detto che ad una scrittura sullo stream corrisponda una immediata
-scrittura sul dispositivo.
-
-Per rispondere ad esigenze diverse, lo standard definisce tre distinte modalità
-in cui può essere eseguita la bufferizzazione, delle quali occorre essere ben
-consapevoli, specie in caso di lettura e scrittura da dispositivi interattivi:
+La bufferizzazione è una delle caratteristiche principali della
+interfaccia degli stream; lo scopo è quello di ridurre al minimo il
+numero di system call (\func{read} o \func{write}) eseguite nelle
+operazioni di input/output. Questa funzionalità è assicurata
+automaticamente dalla libreria, ma costituisce anche una degli aspetti
+più comunemente fraintesi, in particolare per quello che riguarda
+l'aspetto della scrittura dei dati sul file.
+
+I caratteri che vengono scritti su uno stream normalmente vengono
+accumulati in un buffer e poi trasmessi in blocco in maniera asincrona
+rispetto alla scrittura (quello che viene chiamato lo \textsl{scarico}
+dei dati, dall'inglese \textit{flush}) tutte le volte che il buffer
+viene riempito. Un comportamento analogo avviene anche in lettura (cioè
+dal file viene letto un blocco di dati, anche se se ne sono richiesti
+una quantità inferiore), ma la cosa ovviamente ha rilevanza inferiore,
+dato che i dati letti sono sempre gli stessi; in caso di scrittura
+invece, quando si ha un accesso contemporaneo allo stesso file (ad
+esempio da parte di un altro processo) si potranno vedere solo le parti
+effettivamente scritte, e non quelle ancora presenti nel buffer.
+
+Allo stesso modo, se si sta facendo dell'input/output interattivo
+bisognerà tenere presente le caratteristiche delle operazioni di scarico
+dei dati, poiché non è detto che ad una scrittura sullo stream
+corrisponda una immediata scrittura sul dispositivo.
+
+Per rispondere ad esigenze diverse, lo standard definisce tre distinte
+modalità in cui può essere eseguita la bufferizzazione, delle quali
+occorre essere ben consapevoli, specie in caso di lettura e scrittura da
+dispositivi interattivi:
 \begin{itemize}
 \item \textit{unbuffered}: in questo caso non c'è bufferizzazione ed i
   caratteri vengono trasmessi direttamente al file non appena possibile
   (effettuando immediatamente una \func{write}).
 \begin{itemize}
 \item \textit{unbuffered}: in questo caso non c'è bufferizzazione ed i
   caratteri vengono trasmessi direttamente al file non appena possibile
   (effettuando immediatamente una \func{write}).
-\item \textit{line buffered}: in questo caso i caratteri vengono normalmente
-  trasmessi al file in blocco ogni volta che viene incontrato un carattere di
-  \textit{newline} (il carattere ASCII \verb|\n|).
-\item \textit{fully buffered}: in questo caso i caratteri vengono trasmessi da
-  e verso il file in blocchi di dimensione opportuna.
+\item \textit{line buffered}: in questo caso i caratteri vengono
+  normalmente trasmessi al file in blocco ogni volta che viene
+  incontrato un carattere di \textit{newline} (il carattere ASCII
+  \verb|\n|).
+\item \textit{fully buffered}: in questo caso i caratteri vengono
+  trasmessi da e verso il file in blocchi di dimensione opportuna.
 \end{itemize}
 
 \end{itemize}
 
-Lo standard ANSI C specifica inoltre che lo standard output e lo standard
-input siano aperti in modalità \textit{fully buffered} quando non fanno
-riferimento ad un dispositivo interattivo, e che lo standard error non sia mai
-aperto in modalità \textit{fully buffered}.
+Lo standard ANSI C specifica inoltre che lo standard output e lo
+standard input siano aperti in modalità \textit{fully buffered} quando
+non fanno riferimento ad un dispositivo interattivo, e che lo standard
+error non sia mai aperto in modalità \textit{fully buffered}.
 
 Linux, come BSD e SVr4, specifica il comportamento di default in maniera
 ancora più precisa, e cioè impone che lo standard error sia sempre
 
 Linux, come BSD e SVr4, specifica il comportamento di default in maniera
 ancora più precisa, e cioè impone che lo standard error sia sempre
@@ -438,9 +444,10 @@ formattati. Le due funzioni che si usano per l'I/O binario sono:
   elementi inferiore al richiesto.
 \end{functions}
 
   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:
+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:
 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
 int WriteVect(FILE * stream, double * vec, size_t nelem) 
 {
 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
 int WriteVect(FILE * stream, double * vec, size_t nelem) 
 {
@@ -452,15 +459,17 @@ int WriteVect(FILE * stream, double * vec, size_t nelem)
     return nread;
 }
 \end{lstlisting}
     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:
+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:
 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
 struct histogram {
     int nbins; 
     double max, min;
     double * bin;
 } histo; 
 \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) {
 int WriteStruct(FILE * stream, struct histogram * histo, size_t nelem) 
 {
     if ( fwrite(vec, sizeof(*histo), 1, stream) !=1) {
@@ -469,8 +478,18 @@ int WriteStruct(FILE * stream, struct histogram * histo, size_t nelem)
     return nread;
 }
 \end{lstlisting}
     return nread;
 }
 \end{lstlisting}
+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 \func{size * nelem},
+la sola differenza è che le funzioni non ritornano il numero di bytes
+scritti, ma il numero di elementi. 
+
+La funzione \func{fread} legge sempre un numero intero di elementi, se
+si ha un errore o si incontra la fine del file l'oggetto letto
+parzialmente viene scartato
 
 
 
 
+Benché queste funzioni assicurino 
 
 
 \subsection{Input/output a caratteri singoli}
 
 
 \subsection{Input/output a caratteri singoli}