X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filestd.tex;h=9d06757cd1d02302f4a8ff1c372a2c31913308f8;hp=d69d7d42172d8ac3408681e8f1ec5eef98822cc6;hb=c474f4307db945bc45287edd0ea4c2c29374d0ee;hpb=a051e3c3d3b403ee210274d8c2ec7d756c531a21 diff --git a/filestd.tex b/filestd.tex index d69d7d4..9d06757 100644 --- a/filestd.tex +++ b/filestd.tex @@ -1,6 +1,6 @@ %% filestd.tex %% -%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Prefazione", @@ -21,7 +21,7 @@ dell'interfaccia nell'ultima sezione. \section{Introduzione} \label{sec:file_stream_intro} -Come visto in \capref{cha:file_unix_interface} le operazioni di I/O sui file +Come visto in cap.~\ref{cha:file_unix_interface} le operazioni di I/O sui file sono gestibili a basso livello con l'interfaccia standard unix, che ricorre direttamente alle system call messe a disposizione dal kernel. @@ -67,8 +67,8 @@ A parte i dettagli legati alla gestione delle operazioni di lettura e scrittura (sia per quel che riguarda la bufferizzazione, che le formattazioni), i file stream restano del tutto equivalenti ai file descriptor (sui quali sono basati), ed in particolare continua a valere quanto visto in -\secref{sec:file_sharing} a proposito dell'accesso condiviso ed in -\secref{sec:file_access_control} per il controllo di accesso. +sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in +sez.~\ref{sec:file_access_control} per il controllo di accesso. \index{file!stream|)} @@ -93,7 +93,7 @@ includendo l'header file \file{stdio.h}. \subsection{Gli stream standard} \label{sec:file_std_stream} -Ai tre file descriptor standard (vedi \secref{sec:file_std_descr}) +Ai tre file descriptor standard (vedi sez.~\ref{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 @@ -117,10 +117,7 @@ Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono effettivamente tre variabili di tipo \ctyp{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}[stepnumber=0,frame=]{} - fclose(stdout); - stdout = fopen("standard-output-file", "w"); -\end{lstlisting} +\includecodesnip{listati/redir_stdout.c} ma in altri sistemi queste variabili possono essere definite da macro, e se si hanno problemi di portabilità e si vuole essere sicuri, diventa opportuno usare la funzione \func{freopen}. @@ -203,7 +200,7 @@ comporta l'accesso al kernel\footnote{questo vuol dire che lo stream da cui si legge è in modalità \textit{unbuffered}.} viene anche eseguito lo scarico di tutti i buffer degli stream in scrittura. -In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle +In sez.~\ref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle opportune funzioni per controllare le modalità di bufferizzazione e lo scarico dei dati. @@ -213,7 +210,7 @@ dei dati. \label{sec:file_ansi_base_func} Esamineremo in questa sezione le funzioni base dell'interfaccia degli stream, -analoghe a quelle di \secref{sec:file_base_func} per i file descriptor. In +analoghe a quelle di sez.~\ref{sec:file_base_func} per i file descriptor. In particolare vedremo come aprire, leggere, scrivere e cambiare la posizione corrente in uno stream. @@ -248,11 +245,11 @@ Le funzioni che si possono usare per aprire uno stream sono solo tre: Normalmente la funzione che si usa per aprire uno stream è \func{fopen}, essa apre il file specificato nella modalità specificata da \param{mode}, che è una stringa che deve iniziare con almeno uno dei -valori indicati in \tabref{tab:file_fopen_mode} (sono possibili varie +valori indicati in tab.~\ref{tab:file_fopen_mode} (sono possibili varie estensioni che vedremo in seguito). L'uso più comune di \func{freopen} è per redirigere uno dei tre file -standard (vedi \secref{sec:file_std_stream}): il file \param{path} viene +standard (vedi sez.~\ref{sec:file_std_stream}): il file \param{path} viene associato a \param{stream} e se questo è uno stream già aperto viene preventivamente chiuso. @@ -297,7 +294,7 @@ possono essere aperti con le funzioni delle librerie standard del C. \end{table} In realtà lo standard ANSI C prevede un totale di 15 possibili valori -diversi per \param{mode}, ma in \tabref{tab:file_fopen_mode} si sono +diversi per \param{mode}, ma in tab.~\ref{tab:file_fopen_mode} si sono riportati solo i sei valori effettivi, ad essi può essere aggiunto pure il carattere \texttt{b} (come ultimo carattere o nel mezzo agli altri per le stringhe di due caratteri) che in altri sistemi operativi serve a @@ -307,7 +304,7 @@ compatibilit Le \acr{glibc} supportano alcune estensioni, queste devono essere sempre indicate dopo aver specificato il \param{mode} con uno dei valori di -\tabref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per +tab.~\ref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per evitare di sovrascrivere un file già esistente (è analoga all'uso dell'opzione \const{O\_EXCL} in \func{open}), se il file specificato già esiste e si aggiunge questo carattere a \param{mode} la \func{fopen} @@ -322,15 +319,15 @@ opportune funzioni di conversione in lettura e scrittura. Nel caso si usi \func{fdopen} i valori specificati da \param{mode} devono essere compatibili con quelli con cui il file descriptor è stato aperto. Inoltre i modi \cmd{w} e \cmd{w+} non troncano il file. La posizione nello -stream viene impostata a quella corrente nel file descriptor, e le variabili di -errore e di fine del file (vedi \secref{sec:file_io}) sono cancellate. Il file -non viene duplicato e verrà chiuso alla chiusura dello stream. +stream viene impostata a quella corrente nel file descriptor, e le variabili +di errore e di fine del file (vedi sez.~\ref{sec:file_io}) sono cancellate. Il +file non viene duplicato e verrà chiuso alla chiusura dello stream. I nuovi file saranno creati secondo quanto visto in -\secref{sec:file_ownership} ed avranno i permessi di accesso impostati al +sez.~\ref{sec:file_ownership} ed avranno i permessi di accesso impostati al valore \code{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH} (pari a \val{0666}) modificato secondo il valore di \acr{umask} per il processo (si -veda \secref{sec:file_umask}). +veda sez.~\ref{sec:file_umask}). In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è di mezzo una bufferizzazione; per questo motivo lo standard ANSI C @@ -348,7 +345,7 @@ 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 -(si veda \secref{sec:file_buffering_ctrl}) fintanto che non si è effettuato +(si veda sez.~\ref{sec:file_buffering_ctrl}) fintanto che non si è effettuato alcuna operazione di I/O sul file. Uno stream viene chiuso con la funzione \funcd{fclose} il cui prototipo è: @@ -367,7 +364,7 @@ e scarta tutti i dati in ingresso; se era stato allocato un buffer per lo stream questo verrà rilasciato. La funzione effettua lo scarico solo per i dati presenti nei buffer in user space usati dalle \acr{glibc}; se si vuole essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare -una \func{sync} (vedi \secref{sec:file_sync}). +una \func{sync} (vedi sez.~\ref{sec:file_sync}). Linux supporta anche una altra funzione, \funcd{fcloseall}, come estensione GNU implementata dalle \acr{glibc}, accessibile avendo definito @@ -382,7 +379,7 @@ e scarta quelli in ingresso, chiudendo tutti i file. Questa funzione provvista solo per i casi di emergenza, quando si è verificato un errore ed il programma deve essere abortito, ma si vuole compiere qualche altra operazione dopo aver chiuso i file e prima di uscire (si ricordi quanto -visto in \secref{sec:proc_exit}). +visto in sez.~\ref{sec:proc_exit}). \subsection{Lettura e scrittura su uno stream} @@ -394,12 +391,12 @@ scrittura sui file. Sono infatti previste ben tre diverse modalit modalità di input/output non formattato: \begin{enumerate*} \item\textsl{binario} in cui legge/scrive un blocco di dati alla - volta, vedi \secref{sec:file_binary_io}. + volta, vedi sez.~\ref{sec:file_binary_io}. \item\textsl{a caratteri} in cui si legge/scrive un carattere alla volta (con la bufferizzazione gestita automaticamente dalla libreria), - vedi \secref{sec:file_char_io}. + vedi sez.~\ref{sec:file_char_io}. \item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata - dal carattere di newline \verb|'\n'|), vedi \secref{sec:file_line_io}. + dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}. \end{enumerate*} ed inoltre la modalità di input/output formattato. @@ -420,7 +417,7 @@ Siccome la condizione di end-of-file 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 impostato in -una altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del +una altra occasione, (si veda sez.~\ref{sec:sys_errno} per i dettagli del funzionamento di \var{errno}). Per questo motivo tutte le implementazioni delle librerie standard @@ -454,7 +451,7 @@ la funzione \funcd{clearerr}, il cui prototipo corretta la causa di un errore per evitare di mantenere i flag attivi, così da poter rilevare una successiva ulteriore condizione di errore. Di questa funzione esiste una analoga \func{clearerr\_unlocked} che non esegue il blocco -dello stream (vedi \secref{sec:file_stream_thread}). +dello stream (vedi sez.~\ref{sec:file_stream_thread}). \subsection{Input/output binario} @@ -487,40 +484,12 @@ 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}[stepnumber=0,frame=]{} -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} -%\normalsize +\includecodesnip{listati/WriteVect.c} 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}[stepnumber=0,frame=]{} -struct histogram { - int nbins; - double max, min; - double *bin; -} histo; - -int WriteStruct(FILE *stream, struct histogram *histo) -{ - if ( fwrite(histo, sizeof(*histo), 1, stream) !=1) { - perror("Write error"); - } - return nread; -} -\end{lstlisting} -%\normalsize +\includecodesnip{listati/WriteStruct.c} in cui si specifica la dimensione dell'intera struttura ed un solo elemento. @@ -566,7 +535,7 @@ eventuali differenze. Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, \funcd{fread\_unlocked} e \funcd{fwrite\_unlocked} che evitano il lock implicito dello stream, usato per dalla librerie per la gestione delle -applicazioni multi-thread (si veda \secref{sec:file_stream_thread} per i +applicazioni multi-thread (si veda sez.~\ref{sec:file_stream_thread} per i dettagli), i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -613,7 +582,7 @@ differenza viene implementata con una macro, per cui occorre stare attenti a cosa le si passa come argomento, infatti \param{stream} può essere valutato più volte nell'esecuzione, e non viene passato in copia con il -meccanismo visto in \secref{sec:proc_var_passing}; per questo motivo se +meccanismo visto in sez.~\ref{sec:proc_var_passing}; per questo motivo se si passa un'espressione si possono avere effetti indesiderati. Invece \func{fgetc} è assicurata essere sempre una funzione, per questo @@ -739,7 +708,7 @@ successivamente. Infine si tenga presente che \func{ungetc} non altera il contenuto del file, ma opera esclusivamente sul buffer interno. Se si esegue una qualunque delle operazioni di riposizionamento (vedi -\secref{sec:file_fseek}) i caratteri rimandati indietro vengono +sez.~\ref{sec:file_fseek}) i caratteri rimandati indietro vengono scartati. @@ -852,7 +821,7 @@ Come per l'I/O binario e quello a caratteri, anche per l'I/O di linea le \acr{glibc} supportano una serie di altre funzioni, estensioni di tutte quelle illustrate finora (eccetto \func{gets} e \func{puts}), che eseguono esattamente le stesse operazioni delle loro equivalenti, evitando però il lock -implicito dello stream (vedi \secref{sec:file_stream_thread}). Come per le +implicito dello stream (vedi sez.~\ref{sec:file_stream_thread}). Come per le altre forma di I/O, dette funzioni hanno lo stesso nome della loro analoga normale, con l'aggiunta dell'estensione \code{\_unlocked}. @@ -899,21 +868,14 @@ scritta subito, altrimenti il buffer viene allargato usando passata indietro (si noti infatti come per entrambi i parametri si siano usati dei \textit{value result argument}, passando dei puntatori anziché i valori delle variabili, secondo la tecnica spiegata in -\secref{sec:proc_var_passing}). +sez.~\ref{sec:proc_var_passing}). Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL} e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria necessaria a contenere la linea. In tutti i casi si ottiene dalla funzione un puntatore all'inizio del testo della linea letta. Un esempio di codice può essere il seguente: -\begin{lstlisting}[stepnumber=0,frame=]{} - size_t n = 0; - char *ptr = NULL; - int nread; - FILE * file; - ... - nread = getline(&ptr, &n, file); -\end{lstlisting} +\includecodesnip{listati/getline.c} e per evitare memory leak\index{memory leak} occorre ricordarsi di liberare \var{ptr} con una \func{free}. @@ -1032,7 +994,7 @@ La stringa 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. +tab.~\ref{tab:file_format_spec}) che la conclude. \begin{table}[htb] \centering @@ -1069,13 +1031,13 @@ questo ordine: \begin{itemize*} \item uno specificatore del parametro da usare (terminato da un \val{\$}), \item uno o più flag (i cui valori possibili sono riassunti in - \tabref{tab:file_format_flag}) che controllano il formato di stampa della + tab.~\ref{tab:file_format_flag}) che controllano il formato di stampa della conversione, \item uno specificatore di larghezza (un numero decimale), eventualmente seguito (per i numeri in virgola mobile) da un specificatore di precisione (un altro numero decimale), \item uno specificatore del tipo di dato, che ne indica la dimensione (i cui - valori possibili sono riassunti in \tabref{tab:file_format_type}). + valori possibili sono riassunti in tab.~\ref{tab:file_format_type}). \end{itemize*} @@ -1119,7 +1081,7 @@ manuale di \func{printf} e nella documentazione delle \acr{glibc}. Una versione alternativa delle funzioni di output formattato, che permettono di usare il puntatore ad una lista di argomenti (vedi -\secref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e +sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e \funcd{vsprintf}, i cui prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -1142,7 +1104,7 @@ di usare il puntatore ad una lista di argomenti (vedi si vogliono passare ad una routine di stampa, passando direttamente la lista tramite il parametro \param{ap}. Per poter far questo ovviamente la lista dei parametri dovrà essere opportunamente trattata (l'argomento è esaminato in -\secref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento +sez.~\ref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento \param{ap} non sarà più utilizzabile (in generale dovrebbe essere eseguito un \code{va\_end(ap)} ma in Linux questo non è necessario). @@ -1178,7 +1140,7 @@ sono: \end{functions} Entrambe le funzioni prendono come parametro \param{strptr} che deve essere l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà -restituito (si ricordi quanto detto in \secref{sec:proc_var_passing} a +restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a proposito dei \textit{value result argument}) l'indirizzo della stringa allocata automaticamente dalle funzioni. Occorre inoltre ricordarsi di invocare \func{free} per liberare detto puntatore quando la stringa non serve @@ -1295,7 +1257,7 @@ stream sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono: L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file descriptor, ed i parametri, a parte il tipo, hanno lo stesso significato; in particolare \param{whence} assume gli stessi valori già visti in -\secref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1 +sez.~\ref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1 in caso di errore. La funzione \func{rewind} riporta semplicemente la posizione corrente all'inizio dello stream, ma non esattamente equivalente ad una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i @@ -1414,7 +1376,7 @@ operazione ci fosse comunque stata. \subsection{Il controllo della bufferizzazione} \label{sec:file_buffering_ctrl} -Come accennato in \secref{sec:file_buffering} le librerie definiscono una +Come accennato in sez.~\ref{sec:file_buffering} le librerie definiscono una serie di funzioni che permettono di controllare il comportamento degli stream; se non si è specificato nulla, la modalità di buffering viene decisa autonomamente sulla base del tipo di file sottostante, ed i buffer vengono @@ -1481,7 +1443,7 @@ Per evitare che \func{setvbuf} imposti il buffer basta passare un valore \val{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 +opportuni valori elencati in tab.~\ref{tab:file_stream_buf_mode}. Qualora si specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size} vengono sempre ignorati. @@ -1549,7 +1511,7 @@ funzione \funcd{\_flushlbf}, il cui prototipo Si ricordi comunque che lo scarico dei dati dai buffer effettuato da queste funzioni non comporta la scrittura di questi su disco; se si vuole che il kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre -usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}). +usare \func{sync} o \func{fsync} (si veda~sez.~\ref{sec:file_sync}). Infine esistono anche circostanze in cui si vuole scartare tutto l'output pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è: