X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filestd.tex;h=5e6cdecf0f569fa061ca00e40958b9d2cff8343c;hp=df0f1628195187e8754a25e931b3a1a543c591d6;hb=0df8310fbad12660d8de351c7550010943a3a167;hpb=7bb9546e0e9ac077f3bb6ef338bd7657dce1aa62 diff --git a/filestd.tex b/filestd.tex index df0f162..5e6cdec 100644 --- a/filestd.tex +++ b/filestd.tex @@ -30,13 +30,12 @@ Come pi basso livello, che non provvede nessuna forma di formattazione dei dati e nessuna forma di bufferizzazione per ottimizzare le operazioni di I/O. -In \textit{Advanced Programming in the Unix Environment} Stevens descrive una -serie di test sull'influenza delle dimensioni del blocco di dati (il parametro -\param{buf} di \func{read} e \func{write}) nell'efficienza nelle operazioni di -I/O con i file descriptor, evidenziando come le prestazioni ottimali si -ottengano a partire da dimensioni del buffer dei dati pari a quelle dei -blocchi del filesystem (il valore dato dal campo \var{st\_blksize} di -\var{fstat}). +In \cite{APUE} Stevens descrive una serie di test sull'influenza delle +dimensioni del blocco di dati (il parametro \param{buf} di \func{read} e +\func{write}) nell'efficienza nelle operazioni di I/O con i file descriptor, +evidenziando come le prestazioni ottimali si ottengano a partire da dimensioni +del buffer dei dati pari a quelle dei blocchi del filesystem (il valore dato +dal campo \var{st\_blksize} di \var{fstat}). Se il programmatore non si cura di effettuare le operazioni in blocchi di dimensioni adeguate, le prestazioni sono inferiori. La caratteristica @@ -209,10 +208,10 @@ corrente in uno stream. \subsection{Apertura e chiusura di uno stream} \label{sec:file_fopen} -Le funzioni che si possono usare per aprire uno stream sono solo -tre\footnote{\func{fopen} e \func{freopen} fanno parte dello standard - ANSI C, \func{fdopen} è parte dello standard POSIX.1.}, i loro -prototipi sono: +Le funzioni che si possono usare per aprire uno stream sono solo tre: +\func{fopen}, \func{fdopen} e \func{freopen},\footnote{\func{fopen} e + \func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte + dello standard POSIX.1.} i loro prototipi sono: \begin{functions} \headdecl{stdio.h} \funcdecl{FILE *fopen(const char *path, const char *mode)} @@ -323,7 +322,7 @@ processo (si veda \secref{sec:file_umask}). In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è di messo una bufferizzazione; per questo motivo lo standard ANSI C -richiede che ci sia una operazione di posizionamento fra una operazione +richiede che ci sia un'operazione di posizionamento fra un'operazione di output ed una di input o viceversa (eccetto il caso in cui l'input ha incontrato la fine del file), altrimenti una lettura può ritornare anche il risultato di scritture precedenti l'ultima effettuata. @@ -333,7 +332,7 @@ una scrittura una delle funzioni \func{fflush}, \func{fseek}, \func{fsetpos} o \func{rewind} prima di eseguire una rilettura; viceversa nel caso in cui si voglia fare una scrittura subito dopo aver eseguito una lettura occorre prima usare una delle funzioni \func{fseek}, \func{fsetpos} o \func{rewind}. Anche -una operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è +un'operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è sufficiente a garantire la sincronizzazione. Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione @@ -475,6 +474,7 @@ 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: +\footnotesize \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} int WriteVect(FILE *stream, double *vec, size_t nelem) { @@ -486,10 +486,12 @@ int WriteVect(FILE *stream, double *vec, size_t nelem) return nread; } \end{lstlisting} +\normalsize 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: +\footnotesize \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} struct histogram { int nbins; @@ -505,6 +507,7 @@ int WriteStruct(FILE *stream, struct histogram *histo, size_t nelem) return nread; } \end{lstlisting} +\normalsize in cui si specifica la dimensione dell'intera struttura ed un solo elemento. @@ -756,7 +759,6 @@ capo della tastiera), ma \func{gets} sostituisce \verb|\n| con uno zero, mentre \func{fgets} aggiunge uno zero dopo il \textit{newline}, che resta dentro la stringa. Se la lettura incontra la fine del file (o c'è un errore) viene restituito un \macro{NULL}, ed il buffer \param{buf} non viene toccato. - L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la funzione infatti non controlla il numero di byte letti, per cui nel caso la stringa letta superi le dimensioni del buffer, si avrà un @@ -957,11 +959,7 @@ dell'alternativa: La parte più complessa di queste funzioni è il formato della stringa \param{format} che indica le conversioni da fare, da cui poi deriva il numero -dei parametri che dovranno essere passati a seguire. La stringa è costituita -da caratteri normali (tutti eccetto \texttt{\%}), che vengono passati -invariati all'output, e da direttive di conversione, in cui devono essere -sempre presenti il carattere \texttt{\%}, che introduce la direttiva, ed uno -degli specificatori di conversione (riportati in \ntab) che la conclude. +dei parametri che dovranno essere passati a seguire. \begin{table}[htb] \centering @@ -1007,6 +1005,32 @@ degli specificatori di conversione (riportati in \ntab) che la conclude. \label{tab:file_format_spec} \end{table} +La stringa è costituita da caratteri normali (tutti eccetto \texttt{\%}), che +vengono passati invariati all'output, e da direttive di conversione, in cui +devono essere sempre presenti il carattere \texttt{\%}, che introduce la +direttiva, ed uno degli specificatori di conversione (riportati in +\tabref{tab:file_format_spec}) che la conclude. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{10cm}|} + \hline + \textbf{Valore} & \textbf{Significato}\\ + \hline + \hline + \cmd{\#} & Chiede la conversione in forma alternativa. \\ + \cmd{0} & La conversione è riempita con zeri alla sinistra del valore.\\ + \cmd{-} & La conversione viene allineata a sinistra sul bordo del campo.\\ + \cmd{' '}& Mette uno spazio prima di un numero con segno di valore + positivo\\ + \cmd{+} & Mette sempre il segno ($+$ o $-$) prima di un numero.\\ + \hline + \end{tabular} + \caption{I valori dei flag per il formato di \func{printf}} + \label{tab:file_format_flag} +\end{table} + Il formato di una direttiva di conversione prevede una serie di possibili elementi opzionali oltre al \cmd{\%} e allo specificatore di conversione. In generale essa è sempre del tipo: @@ -1032,26 +1056,6 @@ questo ordine: \end{itemize*} -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|l|p{10cm}|} - \hline - \textbf{Valore} & \textbf{Significato}\\ - \hline - \hline - \cmd{\#} & Chiede la conversione in forma alternativa. \\ - \cmd{0} & La conversione è riempita con zeri alla sinistra del valore.\\ - \cmd{-} & La conversione viene allineata a sinistra sul bordo del campo.\\ - \cmd{' '}& Mette uno spazio prima di un numero con segno di valore - positivo\\ - \cmd{+} & Mette sempre il segno ($+$ o $-$) prima di un numero.\\ - \hline - \end{tabular} - \caption{I valori dei flag per il formato di \func{printf}} - \label{tab:file_format_flag} -\end{table} - Dettagli ulteriori sulle varie opzioni possono essere trovati nella man page di \func{printf} e nella documentazione delle \acr{glibc}. @@ -1294,9 +1298,10 @@ pu errore.} \end{functions} -In Linux, a partire dalle glibc 2.1, sono presenti anche le funzioni -\func{fseeko} e \func{ftello}, assolutamente identiche alle precedenti ma con -argomenti di tipo \type{off\_t} anziché di tipo \type{long int}. +In Linux, a partire dalle glibc 2.1, sono presenti anche le due funzioni +\func{fseeko} e \func{ftello}, che assolutamente identiche alle precedenti +\func{fseek} e \func{ftell} ma hanno argomenti di tipo \type{off\_t} anziché +di tipo \type{long int}. @@ -1349,8 +1354,10 @@ puntatore allo stream; questo pu \end{functions} \noindent che permettono di ottenere questa informazione. -Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} servono ad un -uso ancora più specialistico, il loro prototipo è: +La conoscenza dell'ultima operazione effettuata su uno stream aperto è utile +in quanto permette di trarre conclusioni sullo stato del buffer e del suo +contenuto. Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} +servono a tale scopo, il loro prototipo è: \begin{functions} \headdecl{stdio\_ext.h} \funcdecl{int \_\_freading(FILE *stream)} @@ -1362,16 +1369,12 @@ uso ancora pi 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 +Le due funzioni permettono 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. +ancora eseguite operazioni, in questo caso le funzioni rispondono come se una +operazione ci fosse comunque stata. \subsection{Il controllo della bufferizzazione} @@ -1394,7 +1397,7 @@ suo prototipo da \param{mode}, usando \param{buf} come buffer di lunghezza \param{size}. \bodydesc{Restituisce zero in caso di successo, ed un valore qualunque in - caso di errore.} + caso di errore, nel qual caso \var{errno} viene settata opportunamente.} \end{prototype} La funzione permette di controllare tutti gli aspetti della bufferizzazione; @@ -1415,18 +1418,11 @@ pu Dato che la procedura di allocazione manuale è macchinosa, comporta dei rischi (come delle scritture accidentali sul buffer) e non assicura la scelta delle dimensioni ottimali, è sempre meglio lasciare allocare il buffer alle funzioni -di librerie, che sono in grado di farlo in maniera ottimale e trasparente +di libreria, che sono in grado di farlo in maniera ottimale e trasparente all'utente (in quanto la disallocazione avviene automaticamente). Inoltre siccome alcune implementazioni usano parte del buffer per mantenere delle informazioni di controllo, non è detto che le dimensioni dello stesso -coincidano con le dimensioni con cui viene effettuato l'I/O. - -Per evitare che \func{setvbuf} setti il buffer basta passare un valore -\macro{NULL} per \param{buf} e la funzione ignorerà il parametro \param{size} -usando il buffer allocato automaticamente dal sistema. Si potrà comunque -modificare la modalità di bufferizzazione, passando in \param{mode} uno degli -opportuni valori elencati in \ntab. Qualora si specifichi la modalità non -bufferizzata i valori di \param{buf} e \param{size} vengono sempre ignorati. +coincidano con quelle su cui viene effettuato l'I/O. \begin{table}[htb] \centering @@ -1441,11 +1437,19 @@ bufferizzata i valori di \param{buf} e \param{size} vengono sempre ignorati. \macro{\_IOFBF} & \textit{fully buffered}\\ \hline \end{tabular} - \label{tab:file_stream_buf_mode} \caption{Valori del parametro \param{mode} di \func{setvbuf} per il settaggio delle modalità di bufferizzazione.} + \label{tab:file_stream_buf_mode} \end{table} +Per evitare che \func{setvbuf} setti il buffer basta passare un valore +\macro{NULL} per \param{buf} e la funzione ignorerà il parametro \param{size} +usando il buffer allocato automaticamente dal sistema. Si potrà comunque +modificare la modalità di bufferizzazione, passando in \param{mode} uno degli +opportuni valori elencati in \tabref{tab:file_stream_buf_mode}. Qualora si +specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size} +vengono sempre ignorati. + Oltre a \func{setvbuf} le \acr{glibc} definiscono altre tre funzioni per la gestione della bufferizzazione di uno stream: \func{setbuf}, \func{setbuffer} e \func{setlinebuf}, i loro prototipi sono: @@ -1466,9 +1470,9 @@ e \func{setlinebuf}, i loro prototipi sono: \noindent tutte queste funzioni sono realizzate con opportune chiamate a \func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie BSD. Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche - queste sono originarie di Solaris} \func{\_\_flbf} e \func{\_\_fbufsize} che -permettono di leggere le proprietà di bufferizzazione di uno stream; i cui -prototipi sono: + queste funzioni sono originarie di Solaris.} \func{\_\_flbf} e +\func{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione +di uno stream; i cui prototipi sono: \begin{functions} \headdecl{stdio\_ext.h} @@ -1493,7 +1497,7 @@ scelta, si pu \end{prototype} \noindent anche di questa funzione esiste una analoga \func{fflush\_unlocked}\footnote{accessibile definendo \macro{\_BSD\_SOURCE} o - \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}} che non effettua il blocco + \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}.} che non effettua il blocco dello stream. Se \param{stream} è \macro{NULL} lo scarico dei dati è forzato per tutti gli