della massima efficienza.
Per questo motivo l'interfaccia viene chiamata anche interfaccia dei
-\textit{file stream}, dato che non è più necessario doversi preoccupare di dei
-dettagli della comunicazione con il tipo di hardware sottostante (come nel
-caso della dimensione dei blocchi del filesystem), ed un file può essere
-sempre considerato come composto da un flusso continuo (da cui il nome
-\textit{stream}) di dati.
+\textit{file stream}, dato che non è più necessario doversi preoccupare
+dei dettagli della comunicazione con il tipo di hardware sottostante
+(come nel caso della dimensione dei blocchi del filesystem), ed un file
+può essere sempre considerato come composto da un flusso continuo (da
+cui il nome \textit{stream}) di dati.
A parte i dettagli legati alla gestione delle operazioni di lettura e
scrittura (sia per quel che riguarda la bufferizzazione, che le
stream, come la posizione corrente, lo stato del buffer e degli indicatori di
stato e di fine del file.
-Per questo motivo gli utenti non devono mai utilizzare direttamente o allocare
-queste strutture, ma usare sempre puntatori del tipo \type{FILE *} ottenuti
-dalla libreria stessa (tanto che in certi casi il termine di puntatore a file
-è diventato sinonimo di stream).
-
-Tutte le funzioni della libreria che operano sui file accettano come parametri
-solo variabili di questo tipo, che diventa accessibile includendo l'header
+Per questo motivo gli utenti non devono mai utilizzare direttamente o
+allocare queste strutture, ma usare sempre puntatori del tipo \type{FILE
+ *} ottenuti dalla libreria stessa (tanto che in certi casi il termine
+di puntatore a file è diventato sinonimo di stream). Tutte le funzioni
+della libreria che operano sui file accettano come parametri solo
+variabili di questo tipo, che diventa accessibile includendo l'header
file \file{stdio.h}.
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 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}.
\subsection{Le modalità di bufferizzazione}
\func{freopen}.
\end{functions}
-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
-delle stringhe elencate in \tabref{tab:file_fopen_mode}.
+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
+estensioni che vedremo in seguito).
-L'uso di \func{freopen} è in genere per redirigere uno dei tre file standard
-(vedi \secref{sec:file_std_stream}): il file \param{path} viene associato a
-\param{stream} e se questo è uno stream aperto prima viene chiuso.
+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
+associato a \param{stream} e se questo è uno stream già aperto viene
+preventivamente chiuso.
-Infine \func{fdopen} viene usato per associare uno stream ad un file
-descriptor esistente ottenuto tramite una altra funzione (come \func{open},
-\func{dup}, \func{pipe}) e serve quando si vogliono usare gli stream con file
-speciali come le fifo od i socket, che non possono essere aperti con le
-funzioni delle librerie standard del C.
+Infine \func{fdopen} viene usata per associare uno stream ad un file
+descriptor esistente ottenuto tramite una altra funzione (ad esempio con
+una \func{open}, una \func{dup}, o una \func{pipe}) e serve quando si
+vogliono usare gli stream con file come le fifo o i socket, che non
+possono essere aperti con le funzioni delle librerie standard del C.
\begin{table}[htb]
\centering
\textbf{Valore} & \textbf{Significato}\\
\hline
\hline
- \texttt{r} & Il file viene aperto in sola lettura; lo stream è posizionato
- all'inizio del file.\\
- \texttt{r+} & Il file viene aperto in lettura e scrittura; lo stream è
- posizionato all'inizio del file. \\
+ \texttt{r} & Il file viene aperto, l'accesso viene posto in sola
+ lettura, lo stream è posizionato all'inizio del file.\\
+ \texttt{r+} & Il file viene aperto, l'accesso viene posto in lettura e
+ scrittura, lo stream è posizionato all'inizio del file. \\
% \hline
- \texttt{w} & Il file viene troncato a lunghezza nulla (o creato se non
- esiste), ed aperto in sola lettura; lo stream è posizionato all'inizio del
- file.\\
- \texttt{w+} & Il file viene troncato a lunghezza nulla (o creato se non
- esiste), ed aperto in scrittura e lettura; lo stream è posizionato
- all'inizio del file.\\
+ \texttt{w} & Il file viene aperto e troncato a lunghezza nulla (o
+ creato se non esiste), l'accesso viene posto in sola scrittura, lo
+ stream è posizionato all'inizio del file.\\
+ \texttt{w+} & Il file viene aperto e troncato a lunghezza nulla (o
+ creato se non esiste), l'accesso viene posto in scrittura e lettura,
+ lo stream è posizionato all'inizio del file.\\
% \hline
- \texttt{a} & Il file è aperto in \textit{append mode} in sola scrittura
- (o creato se non esiste). \\
- \texttt{a+} & Il file è aperto in \textit{append mode} in lettura e
- scrittura (o creato se non esiste). \\
+ \texttt{a} & Il file viene aperto (o creato se non esiste) in
+ \textit{append mode}, l'accesso viene posto in sola scrittura. \\
+ \texttt{a+} & Il file viene aperto (o creato se non esiste) in
+ \textit{append mode}, l'accesso viene posto in lettura e scrittura. \\
\hline
\end{tabular}
- \caption{Modalità di apertura di uno stream}
+ \caption{Modalità di apertura di uno stream dello standard ANSI C che
+ sono sempre presenti in qualunque sistema POSIX}
\label{tab:file_fopen_mode}
\end{table}
distinzione non esiste e il valore viene accettato solo per
compatibilità, ma non ha alcun effetto.
+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
+evitare di sovrascrivere un file già esistente (è analoga all'uso
+dell'opzione \macro{O\_EXCL} in \func{open}), se il file specificato già
+esiste e si aggiunge questo carattere a \param{mode} la \func{fopen}
+fallisce.
+
+Un'altra estensione serve a supportare la localizzazione, quando si
+aggiunge a \param{mode} una stringa della forma \verb|",ccs=STRING"| il
+valore \verb|STRING| è considerato il nome di una codifica dei caratteri
+e \func{fopen} marca il file per l'uso dei caratteri estesi e abilita le
+opportune funzioni di conversione in lettura e scrittura.
+
Inoltre 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 settata a quella
corrente nel file descriptor, e le variabili di errore e di fine del
-file sono cancellate. Il file non viene duplicato e verrà chiuso alla
-chiusura dello stream.
+file (vedi \secref{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 settati al
richiede che ci sia una operazione di posizionamento fra una 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.
+il risultato di scritture precedenti l'ultima effettuata.
Per questo motivo è una buona pratica (e talvolta necessario) far seguire ad
una scrittura una delle funzioni \func{fflush}, \func{fseek}, \func{fsetpos} o
funzione che è fallita (\func{close}, \func{write} o \func{fflush}).
\end{prototype}
-La funzione effettua uno scarico di tutti i dati presenti nei buffer di uscita
-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 essere
-sicuri che il kernel forzi la scrittura su disco occorrerà effettuare .
+La funzione effettua uno scarico di tutti i dati presenti nei buffer di
+uscita 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}.
Linux supporta, come estensione implementata dalle \acr{glibc}, anche una
altra funzione, \func{fcloseall}, che serve a chiudere tutti i file, il suo
ricchezza delle funzioni disponibili per le operazioni di lettura e
scrittura sui file. Sono infatti previste ben tre diverse modalità
modalità di input/output non formattato:
-\begin{enumerate}
+\begin{enumerate*}
\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
\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}.
-\end{enumerate}
+\end{enumerate*}
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}.
+A differenza dell'interfaccia dei file descriptor, con gli stream 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
\type{FILE}, il flag di \textit{end-of-file}, che segnala che si è
raggiunta la fine del file in lettura, e quello di errore, che segnala
la presenza di un qualche errore nelle operazioni di input/output;
-questi flag possono essere riletti dalle funzioni:
+questi due flag possono essere riletti dalle funzioni:
\begin{functions}
\headdecl{stdio.h}
\funcdecl{int feof(FILE *stream)}
\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
+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:
\begin{functions}
}
\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.
+elemento.
-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
+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 byte scritti,
+ma il numero di elementi.
+La funzione \func{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 settata alla fine del file (e non a quella corrispondente
+alla quantità di dati letti).
+
+In caso di errore (o fine del file per \func{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 \func{feof} e \func{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 \cmd{gcc}) possono
+anche scegliere se ottimizzare l'occupazione di spazio, impacchettando
+più strettamente i dati, o la velocità inserendo opportuni
+\textit{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
+essere 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 \acr{glibc} definiscono altre due funzioni per l'I/O binario, 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 dettagli).
-Benché queste funzioni assicurino
+\begin{functions}
+ \headdecl{stdio.h}
+
+ \funcdecl{size\_t fread\_unlocked(void * ptr, size\_t size, size\_t
+ nmemb, FILE * stream)}
+
+ \funcdecl{size\_t fwrite\_unlocked(const void * ptr, size\_t size,
+ size\_t nmemb, FILE * stream)}
+
+ Le funzioni sono identiche alle analoghe \func{fread} e \func{fwrite}
+ ma non acquisiscono il lock implicito sullo stream.
+\end{functions}
+\noindent entrambe le funzioni sono estensioni GNU previste solo dalle
+ \acr{glibc}.
\subsection{Input/output a caratteri singoli}
\section{Funzioni avanzate}
\label{sec:file_stream_adv_func}
-In questa sezione esamineremo le funzioni che permettono di controllare alcune
-caratteristiche più particolari degli stream, come la lettura degli attributi,
-le modalità di bufferizzazione, etc.
+In questa sezione esamineremo le funzioni che permettono di controllare
+alcune caratteristiche più particolari degli stream, come la lettura
+degli attributi, le modalità di bufferizzazione, etc.
\subsection{Le funzioni di controllo}
In certi casi può essere necessario sapere se un certo stream è accessibile in
lettura o scrittura. In genere questa informazione non è disponibile, e si
deve ricordare come il file è stato aperto. La cosa può essere complessa se le
-operazioni vengono effettuate un una subroutine, che a questo punto
+operazioni vengono effettuate in una subroutine, che a questo punto
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:
stream; se non si è
+\subsection{Gli stream e i thread}
+\label{sec:file_stream_thread}
+
+Gli stream possono essere usati in applicazioni multi-thread allo stesso
+modo in cui sono usati nelle applicazioni normali, ma si deve essere
+consapovoli delle possibili complicazioni anche quando non si usano i
+thread, dato che l'implementazione delle librerie è influenzata
+pesantemente dalle richieste necessarie per garantirne l'uso coi thread.
+
+
+
+\begin{functions}
+ \headdecl{stdio.h}
+
+ \funcdecl{void flockfile(FILE * stream)} Esegue l'acquisizione del
+ lock dello stream \param{stream}, bloccandosi in caso il lock non
+ disponibile.
+
+ \funcdecl{int ftrylockfile(FILE * stream)} Tenta l'acquisizione del
+ lock dello stream \param{stream}, senza bloccarsi in caso il lock non sia
+ disponibile. Ritorna zero in caso di acquisizione del lock, diverso da
+ zero altrimenti.
+
+ \funcdecl{void funlockfile(FILE * stream)} Rilascia il lock dello
+ stream \param{stream}.
+\end{functions}
+
+
\subsection{Dettagli dell'implementazione}
\label{sec:file_stream_details}