b761d99661947ed6bfe991e486a54505537e37e3
[gapil.git] / filestd.tex
1 \chapter{I file: l'interfaccia standard ANSI C}
2 \label{cha:files_std_interface}
3
4 Esamineremo in questo capitolo l'interfaccia standard ANSI C per i file,
5 quella che viene comunemente detta interfaccia degli \textit{stream}.
6 Dopo una breve sezione introduttiva tratteremo le funzioni base per la
7 gestione dell'input/output, mentre tratteremo le caratteristiche più avanzate
8 dell'interfaccia nell'ultima sezione.
9
10
11 \section{Introduzione}
12 \label{sec:file_stream_intro}
13
14 Come visto in \capref{cap:file_unix_interface} le operazioni di I/O sui file
15 sono gestibili a basso livello con l'interfaccia standard unix, che ricorre
16 direttamente alle system call messe a disposizione dal kernel.
17
18 Questa interfaccia però non provvede le funzionalità previste dallo standard
19 ANSI C, che invece sono realizzate attraverso opportune funzioni di libreria,
20 queste, insieme alle altre funzioni definite dallo standard, vengono a
21 costituire il nucleo\footnote{queste funzioni sono state implementate la prima
22   volta da Ritchie nel 1976 e da allora sono rimaste sostanzialmente
23   immutate.} delle \acr{glibc}.
24
25
26 \subsection{I \textit{file stream}}
27 \label{sec:file_stream}
28
29 Come più volte ribadito l'interfaccia dei file descriptor è una interfaccia di
30 basso livello, che non provvede nessuna forma di formattazione dei dati e
31 nessuna forma di bufferizzazione per ottimizzare le operazioni di I/O.
32
33 In \textit{Advanced Programming in the Unix Environment} Stevens descrive una
34 serie di test sull'influenza delle dimensioni del blocco di dati (il parametro
35 \param{buf} di \func{read} e \func{write}) nell'efficienza nelle operazioni di
36 I/O con i file descriptor, evidenziando come le prestazioni ottimali si
37 ottengano a partire da dimensioni del buffer dei dati pari a quelle dei
38 blocchi del filesystem (il valore dato dal campo \var{st\_blksize} di
39 \var{fstat}).
40
41 Se il programmatore non si cura di effettuare le operazioni in blocchi di
42 dimensioni adeguate, le prestazioni sono inferiori.  La caratteristica
43 principale dell'interfaccia degli stream è che essa provvede da sola alla
44 gestione dei dettagli della bufferizzazione e all'esecuzione delle operazioni
45 di lettura e scrittura in blocchi di dimensioni appropriate all'ottenimento
46 della massima efficienza.
47
48 Per questo motivo l'interfaccia viene chiamata anche interfaccia dei
49 \textit{file stream}, dato che non è più necessario doversi preoccupare di dei
50 dettagli della comunicazione con il tipo di hardware sottostante (come nel
51 caso della dimensione dei blocchi del filesystem), ed un file può essere
52 sempre considerato come composto da un flusso continuo (da cui il nome
53 \textit{stream}) di dati.
54
55 A parte i dettagli legati alla gestione delle operazioni di lettura e
56 scrittura (sia per quel che riguarda la bufferizzazione, che le
57 formattazioni), i file stream restano del tutto equivalenti ai file descriptor
58 (sui quali sono basati), ed in particolare continua a valere quanto visto in
59 \secref{sec:file_sharing} a proposito dell'accesso condiviso ed in
60 \secref{sec:file_access_control} per il controllo di accesso.
61
62
63 \subsection{Gli oggetti \type{FILE}}
64 \label{sec:file_FILE}
65
66 Per ragioni storiche la struttura di dati che rappresenta uno stream è stata
67 chiamata \type{FILE}, questi oggetti sono creati dalle funzioni di libreria e
68 contengono tutte le informazioni necessarie a gestire le operazioni sugli
69 stream, come la posizione corrente, lo stato del buffer e degli indicatori di
70 stato e di fine del file.
71
72 Per questo motivo gli utenti non devono mai utilizzare direttamente o allocare
73 queste strutture, ma usare sempre puntatori del tipo \type{FILE *} ottenuti
74 dalla libreria stessa (tanto che in certi casi il termine di puntatore a file
75 è diventato sinonimo di stream). 
76
77 Tutte le funzioni della libreria che operano sui file accettano come parametri
78 solo variabili di questo tipo, che diventa accessibile includendo l'header
79 file \file{stdio.h}.
80
81
82
83 \subsection{Gli stream standard}
84 \label{sec:file_std_stream}
85
86 Ai tre file descriptor standard (vedi \secref{sec:file_std_descr}) aperti per
87 ogni processo, corrispondono altrettanti stream, che rappresentano i canali
88 standard di input/output prestabiliti; anche questi tre stream sono
89 idetificabili attraverso dei nomi simbolici definiti nell'header
90 \file{stdio.h} che sono:
91
92 \begin{itemize}
93 \item \var{FILE * stdin} Lo \textit{standard input} cioè lo stream da cui
94   il processo riceve ordinariamente i dati in ingresso. Normalmente è associato
95   dalla shell all'input del terminale e prende i caratteri dalla tastiera.
96 \item \var{FILE * stdout} Lo \textit{standard input} cioè lo stream su cui
97   il processo invia ordinariamente i dati in uscita. Normalmente è associato
98   dalla shell all'output del terminale e scrive sullo schermo.
99 \item \var{FILE * stderr} Lo \textit{standard input} cioè lo stream su cui
100   il processo è supposto inviare i messaggi di errore. Normalmente anch'esso
101   è associato dalla shell all'output del terminale e scrive sullo schermo.
102 \end{itemize}
103
104 Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono effettivamente
105 tre variabili di tipo \type{FILE *} che possono essere usate come tutte le
106 altre, ad esempio si può effettuare una redirezione dell'output di un
107 programma con il semplice codice:
108 \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
109     fclose (stdout);
110     stdout = fopen ("standard-output-file", "w");
111 \end{lstlisting}
112 ma in altri sistemi possono essere definite come macro, se si hanno problemi
113 di portabilità e si vuole essere sicuri, diventa opportuno usare la funzione
114 \func{freopen}.
115
116
117 \subsection{Le modalità di bufferizzazione}
118 \label{sec:file_buffering}
119
120 La bufferizzazione è una delle caratteristiche principali della interfaccia
121 degli stream; lo scopo è quello di ridurre al minimo il numero di system call
122 (\func{read} o \func{write}) eseguite nelle operazioni di input/output. Questa
123 funzionalità è assicurata automaticamente dalla libreria, ma costituisce anche
124 una degli aspetti più comunemente fraintesi, in particolare per quello che
125 riguarda l'aspetto della scrittura dei dati sul file.
126
127 I caratteri che vengono scritti su uno stream normalmente vengono accumulati
128 in un buffer e poi trasmessi in blocco in maniera asincrona rispetto alla
129 scrittura (quello che viene chiamato il \textit{flush} dei dati) tutte le
130 volte che il buffer viene riempito. Un comportamento analogo avviene anche in
131 lettura (cioè dal file viene letto un blocco di dati, anche se se ne sono
132 richiesti una quantità inferiore), ma la cosa ovviamente ha rilevanza
133 inferiore, dato che i dati letti sono sempre gli stessi; in caso di scrittura
134 invece, quando si ha un accesso contemporaneo allo stesso file (ad esempio da
135 parte di un altro processo) si potranno vedere solo le parti effettivamente
136 scritte, e non quelle ancora presenti nel buffer. 
137
138 Allo stesso modo, se si sta facendo dell'input/output interattivo bisognerà
139 tenere presente le caratteristiche delle operazioni di \textit{flush} dei
140 dati, poiché non è detto che ad una scrittura sullo stream corrisponda una
141 immediata scrittura sul dispositivo.
142
143 Per risondere ad esigenze diverse, lo standard definisce tre distinte modalità
144 in cui può essere eseguita la bufferizzazione, delle quali occorre essere ben
145 consapevoli, specie in caso di lettura e scrittura da dispositivi interattivi:
146 \begin{itemize}
147 \item \textit{unbuffered}: in questo caso non c'è bufferizzazione ed i
148   caratteri vengono trasmessi direttamente al file non appena possibile
149   (effettuando immediatamente una \func{write}).
150 \item \textit{line buffered}: in questo caso i caratteri vengono normalmente
151   trasmessi al file in blocco ogni volta che viene incontrato un carattere di
152   \textit{newline} (il carattere ASCII \verb|\n|).
153 \item \textit{fully buffered}: in questo caso i caratteri vengono trasmessi da
154   e verso il file in blocchi di dimensione opportuna.
155 \end{itemize}
156
157 Lo standard ANSI C specifica inoltre che lo standard output e lo standard
158 input siano aperti in modalità \textit{fully buffered} quando non fanno
159 riferimento ad un dispositivo interattivo, e che lo standard error non sia mai
160 aperto in modalità \textit{fully buffered}.
161
162 Linux, come BSD e SVr4, specifica il comportamento di default in maniera
163 ancora più precisa, e cioè impone che lo standard error sia sempre
164 \textit{unbuffered} (in modo che i messaggi di errore siano mostrati il più
165 rapidamente possibile) e che standard input e standard output siano aperti in
166 modalità \textit{line buffered} quando sono associati ad un terminale (od
167 altro dispositivo interattivo) ed in modalità \textit{fully buffered}
168 altrimenti.
169
170 Il comportamento specificato per standard input e standard output vale anche
171 per tutti i nuovi stream aperti da un processo; la selezione comunque avviene
172 automaticamente, e la libreria apre lo stream nella modalità più opportuna a
173 seconda del file o del dispositivo scelto.
174
175 La modalità \textit{line buffered} è quella che necessita di maggiori
176 chiarimenti e attenzioni per quel che concerne il suo funzionamento. Come già
177 accennato nella descrizione, \emph{di norma} i dati vengono inviati al kernel
178 alla ricezione di un carattere di a capo; questo non è vero in tutti i casi,
179 infatti, dato che le dimensioni del buffer usato dalle librerie sono fisse, se
180 le si eccedono si può avere un \textit{flush} dei dati anche prima che sia
181 stato inviato un carattere di \textit{newline}.
182
183 Un secondo punto da tenere presente, particolarmente quando si ha a che fare
184 con I/O interattivo, è che quando si effettua una lettura su uno stream che
185 comporta l'accesso al kernel\footnote{questo vuol dire sempre se lo stream da
186   cui si legge è in modalità \textit{unbuffered}} viene anche eseguito il
187 \textit{flush} di tutti i buffer degli stream in scrittura. 
188
189 In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
190 opportune funzioni per controllare le modalità di bufferizzazione ed il
191 \textit{flush} dei dati.
192
193
194
195 \section{Funzioni base}
196 \label{sec:file_ansi_base_func}
197
198 Esamineremo in questa sezione le funzioni base dell'interfaccia degli stream,
199 analoghe a quelle di \secref{sec:file_base_func} per i file descriptor. In
200 particolare vedremo come aprire, leggere, scrivere e cambiare la posizione
201 corrente in uno stream.
202
203 \subsection{Apertura e chiusura di uno stream}
204 \label{sec:file_fopen}
205
206
207 \subsection{Lettura e scrittura su uno stream}
208 \label{sec:file_io}
209
210
211 \subsection{Posizionamento su uno stream}
212 \label{sec:file_fseek}
213
214
215 \subsection{Input/output binario}
216 \label{sec:file_binary_io}
217
218
219 \subsection{Input/output di linea}
220 \label{sec:file_line_io}
221
222
223 \subsection{Input/output formattato}
224 \label{sec:file_formatted_io}
225
226
227 \subsection{Chiusura di uno stream}
228 \label{sec:file_fclose}
229
230
231 \section{Funzioni avanzate}
232 \label{sec:file_stream_adv_func}
233
234
235 \subsection{Il controllo della bufferizzazione}
236 \label{sec:file_buffering_ctrl}
237
238 Come accennato in \secref{sec:file_buffering} le librerie definiscono una
239 serie di funzioni che permettono di controllare il comportamento degli
240 stream; se non si è 
241
242
243 \subsection{Dettagli dell'implementazione}
244 \label{sec:file_stream_details}
245
246
247 \subsection{File temporanei}
248 \label{sec:file_temp_file}
249
250
251 \subsection{Efficienza}
252 \label{sec:file_stream_efficiency}
253
254
255
256
257
258
259
260
261