X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filestd.tex;h=2a22545a15e690ba79c4eeeefedda7601eb4c78e;hp=6730757a57cdb01d0fbea3d4153e3cf06cefaa89;hb=ab3134c16a7dfcdcb3a80483bf2e80c6e61f48f8;hpb=c35e7552a4a8ef0b39b306f516c00aca1b5a02d3 diff --git a/filestd.tex b/filestd.tex index 6730757..2a22545 100644 --- a/filestd.tex +++ b/filestd.tex @@ -353,8 +353,8 @@ 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} -\item\textsl{a blocchi} in cui legge/scrive un blocco di dati alla - volta, vedi \secref{sec:file_block_io}. +\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 carattere di newline \verb|\n|) alla volta, vedi \secref{sec:file_line_io}. @@ -362,23 +362,27 @@ modalit volta (con la bufferizzazione gestita automaticamente dalla libreria), vedi \secref{sec:file_char_io}. \end{enumerate} -e una 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}. - -Dato che le funzioni dell'interfaccia degli stream sono funzioni di -libreria, esse non settano la variabile \var{errno}, che mantiene il -valore settato dalla system call che ha riportato l'errore, ma siccome -la condizione di end-of-file è anch'essa segnalata come errore, non -esisterebbe alcuna possibilità di distinguerla da un errore (\var{errno} -potrebbe essere stata settata in una altra occasione, vedi -\secref{sec:sys_errno}). +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}. + +Dato che le funzioni dell'interfaccia degli stream sono funzioni di libreria +che si appoggiano a delle system call, esse non settano direttamente la +variabile \var{errno}, che mantiene il valore settato dalla system call che ha +riportato l'errore. + +Siccome la condizione di end-of-file è anch'essa segnalata come errore, nasce +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 settato in una +altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del +funzionamento di \var{errno}). Per questo motivo tutte le implementazioni delle librerie standard mantengono per ogni stream almeno due flag all'interno dell'oggetto @@ -397,11 +401,12 @@ questi flag possono essere riletti dalle funzioni: flag sono settati. \end{functions} \noindent si tenga presente comunque che la lettura di questi flag segnala -soltanto che si è avuto un errore, o si è raggiunta la fine del file, in -una precedente operazione sullo stream. +soltanto che c'è stato un errore, o che si è raggiunta la fine del file in una +qualunque operazione sullo stream, il controllo quindi deve essere effettuato +ogni volta che si chiama una funzione di libreria. -Entrambi i flag (di errore e di end-of-file) possono essere cancellati -usando la funzione \func{clearerr}, il cui prototipo è: +Entrambi i flag (di errore e di end-of-file) possono essere cancellati usando +la funzione \func{clearerr}, il cui prototipo è: \begin{prototype}{stdio.h}{void clearerr( FILE *stream)} Cancella i flag di errore ed end-of-file di \param{stream}. \end{prototype} @@ -410,14 +415,70 @@ corretta la causa di un errore per evitare di mantenere i flag attivi, così da poter rilevare una successiva ulteriore condizione di errore. -\subsection{Input/output a blocchi} -\label{sec:file_block_io} +\subsection{Input/output binario} +\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 +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} + \headdecl{stdio.h} + \funcdecl{size\_t fread(void * ptr, size\_t size, + size\_t nmemb, FILE * stream)} + \funcdecl{size\_t fwrite(const void * + ptr, size\_t size, size\_t nmemb, FILE * stream)} + + Le funzioni rispettivamente leggono e scrivono \param{nmemb} elementi + di dimensione \param{size} dal buffer \param{ptr} al file \param{stream}. + + Entrambe le funzioni ritornano il numero di elementi letti o scritti, + in caso di errore o fine del file viene restituito un numero di + 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: +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} +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} +nel qual caso devono essere specificate dimensione e numero degli +elementi del vettore; nel caso di una struttura invece si avrà un +qualcosa tipo: +\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) { + perror("Write error"); + } + return nread; +} +\end{lstlisting} + + \subsection{Input/output a caratteri singoli} \label{sec:file_char_io} + + \subsection{Input/output di linea} \label{sec:file_line_io} @@ -464,7 +525,30 @@ stream; questo pu scrittura. \end{functions} -Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} servono +Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} servono ad un +uso ancora più specialistico, il loro prototipo è: +\begin{functions} + \headdecl{stdio\_ext.h} + \funcdecl{int \_\_freading (FILE * stream)} + Restituisce un valore diverso da zero se \param{stream} è aperto in sola + lettura o se l'ultima operazione è stata di lettura. + + \funcdecl{int \_\_fwriting(FILE * stream)} + Restituisce un valore diverso da zero se \param{stream} è aperto in sola + 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 +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. + \subsection{Il controllo della bufferizzazione} \label{sec:file_buffering_ctrl}