Linguaggio C: input e output da file.

annuncio pubblicitario
Input e Output in C
1
Anno accademico 2010-2011
Sommario
• Input e output
 I flussi di I/O
 L’uso di buffer
 Apertura e chiusura di file
 Lettura e scrittura di dati
 La selezione di un metodo di I/O
 I/O non bufferizzato
 L’accesso diretto a file
2
Anno accademico 2010-2011
Introduzione
• La gestione dell’I/O su file è uno degli aspetti più complessi dei
linguaggi di programmazione, perché strettamente correlato con le
particolari modalità di accesso a file ed alle periferiche dettate dal
sistema operativo  difficoltà nella progettazione di servizi di I/O
portabili
• Storicamente, l’apposita libreria di runtime del C e la libreria di
I/O di UNIX erano parzialmente sovrapposte: tuttavia, la libreria C
tratta l’I/O bufferizzato, contrariamente alla libreria UNIX
• Le funzioni ANSI di I/O sono tutte bufferizzate (con possibilità di
modifica della dimensione del buffer)
• Le funzioni ANSI di I/O operano inoltre una distinzione tra accesso
a file in modalità binaria o testuale; in ambiente UNIX la
distinzione è poco significativa poiché UNIX tratta file binari e file
di testo alla stessa stregua  come sequenze di byte (in altri
sistemi operativi, tale distinzione è invece importante)
Anno accademico 2010-2011
3
I flussi di I/O  1
• Il linguaggio C non distingue tra periferiche e file su disco: in
entrambi i casi le operazioni di I/O sono realizzate attraverso
flussi o stream di I/O associati a file o periferiche
• Un flusso di I/O è una sequenza ordinata di byte: la lettura e
la scrittura di un file o di una periferica implicano la lettura/
scrittura di dati da/su un flusso
Sorgente C
Flusso
File
I flussi di I/O: i programmi C accedono ai dati memorizzati in file
attraverso array monodimensionali di caratteri, detti flussi di I/O
Anno accademico 2010-2011
4
I flussi di I/O  2
• Per eseguire l’I/O, è necessario associare un flusso ad un
file o a una periferica
 occorre dichiarare un puntatore alla struttura FILE
• La struttura FILE, definita in stdio.h, è costituita da
campi che contengono informazioni quali il nome del file, la
modalità di accesso, il puntatore al prossimo carattere nel
flusso
• I campi della struttura FILE, istanziati all’atto dell’apertura
di un flusso (o in fase di utilizzo), sono dipendenti dall’implementazione e differiscono per sistemi operativi diversi
5
Anno accademico 2010-2011
I flussi di I/O  3
• Le strutture FILE forniscono
informazioni necessarie per la
meccanismo di accesso ad un
struttura FILE, detto puntatore a
al sistema operativo le
gestione dei file: l’unico
flusso è il puntatore alla
file
• Il puntatore a file deve essere dichiarato nel programma,
contiene l’identificatore del flusso restituito da una chiamata
alla fopen(), e viene utilizzato per leggere, scrivere e
chiudere il flusso
• Ciascun programma può aprire più flussi simultaneamente,
nel rispetto dei limiti imposti dalla particolare implementazione
6
Anno accademico 2010-2011
I flussi di I/O  4
• Uno dei campi della struttura FILE è un indicatore di
posizione nel file, che punta al successivo byte da leggere o
scrivere: a fronte di operazioni di lettura/scrittura, il sistema
operativo modifica conseguentemente l’indicatore di posizione
• L’indicatore di posizione del file non può essere manipolato
direttamente (in maniera portabile), ma può essere letto e
modificato tramite funzioni di libreria, permettendo accessi al
flusso non sequenziali
• Attenzione: il puntatore a file identifica un flusso aperto, che è
connesso ad un file o a una periferica, l’indicatore di posizione
nel file identifica uno specifico byte all’interno di un flusso
7
Anno accademico 2010-2011
I flussi standard
• Esistono tre flussi standard, che vengono aperti automaticamente per ogni programma: stdin, stdout, stderr
• I flussi standard sono connessi al terminale, per default, ma
molti sistemi operativi ne permettono la redirezione (ad es.,
è possibile inviare messaggi di errore ad un file per
effettuare diagnostica)
• Le funzioni printf() e scanf() utilizzano i flussi
standard di I/O; possono essere utilizzate anche per fare
I/O su/da file, ridirigendo stdin e stdout a file per mezzo
della funzione freopen()
• Tuttavia, esistono le funzioni di libreria apposite,
fprintf() e fscanf(), che permettono di specificare il
flusso su cui operare
8
Anno accademico 2010-2011
I formati testo e binario
• I dati possono essere acceduti in modalità testo o binaria:
 Un flusso testuale è composto da una sequenza di linee,
concluse da newline (sistemi operativi diversi possono
memorizzare linee con formati diversi, utilizzando un carattere
differente di terminazione linea)
 I flussi standard sono testuali
 In formato binario il compilatore non effettua alcuna interpre-
tazione dei byte: i bit sono letti e scritti come un flusso
continuo
 I flussi binari sono utilizzati quando è fondamentale preservare
l’esatto contenuto del file
9
Anno accademico 2010-2011
L’uso del buffer  1
• Confrontate con la memoria centrale, le unità di memoria di
massa sono estremamente lente: nei programmi, il tempo
richiesto per accedere alle periferiche eccede largamente il
tempo impiegato dalla CPU per i calcoli
• È di fondamentale importanza ridurre il numero di operazioni
di lettura/scrittura, mediante tecniche di bufferizzazione
• Un buffer è un’area di memoria in cui i dati sono memorizzati
temporaneamente, prima di essere inviati a destinazione
• Mediante l’uso di buffer, il sistema operativo può limitare il
numero di accessi effettivi alla memoria di massa
• Tutti i sistemi operativi utilizzano buffer per leggere/scrivere
su unità di I/O: l’accesso a disco, per esempio, avviene con
“granularità di blocco”, con blocchi di dimensione 512/4096
byte
10
Anno accademico 2010-2011
L’uso del buffer  2
• Le librerie di runtime del C contengono un ulteriore livello
di bufferizzazione che può assumere due forme distinte:
bufferizzazione a linee e bufferizzazione a blocchi
 Nella bufferizzazione a linee, il sistema immagazzina i caratteri
fino a quando si incontra un newline (o il buffer è pieno),
inviando l’intera linea al sistema operativo (ciò che accade per
l’inserimento da tastiera)
 Nella bufferizzazione a blocchi, il sistema immagazzina i
caratteri fino a riempire un blocco, trasferendolo quindi al
sistema operativo
• Tutti i flussi di I/O a file utilizzano una bufferizzazione a blocchi, i flussi riferiti a terminale sono dipendenti dal sistema
operativo, ma sono o non bufferizzati o bufferizzati a linee
11
Anno accademico 2010-2011
L’uso del buffer  3
• Le librerie standard di I/O del C comprendono un gestore di buffer
che mantiene il buffer in memoria il più a lungo possibile: se si
accede alla stessa porzione di un flusso più volte, si ha alta
probabilità che il flusso sia stato mantenuto nella memoria centrale
(si possono verificare problemi di accesso concorrente, gestibili via
sistema operativo, se il file è condiviso da più processi)
• Sia nel caso di bufferizzazione a righe che a blocchi, è possibile
richiedere esplicitamente al sistema operativo di forzare l’invio del
buffer a destinazione in un momento qualsiasi, per mezzo della
funzione fflush()
• Il C consente di personalizzare il meccanismo di bufferizzazione
(modificando le dimensioni del buffer) fino ad eliminarla, ponendo
la dimensione del buffer a zero
12
Anno accademico 2010-2011
Il file header stdio.h
• Per utilizzare le funzioni di I/O è necessario includere il file
header stdio.h che contiene:
 Le dichiarazioni dei prototipi di tutte le funzioni di I/O
 La dichiarazione della struttura FILE
 Le macro costanti, come stdin, stdout, stderr, EOF
• EOF
corrisponde al valore restituito dalle funzioni di I/O in
corrispondenza dell’identificatore di fine file
• Nota: La definizione di NULL, per l’ANSI C, è invece
contenuta nel file stddef.h
#ifndef NULL
#define NULL (void *) 0
#endif
Anno accademico 2010-2011
13
La gestione degli errori
• Ogni funzione di I/O restituisce
un valore speciale in caso di
errore: alcune restituiscono zero,
altre un valore diverso da zero o
EOF
• Per ogni flusso aperto, esistono
due campi booleani nella struttura
FILE che registrano condizioni di
errore o di fine file
• Si può accedere ai campi di fine
file e di errore utilizzando le
funzioni feof() e ferror()
• La funzione clearerr() pone
entrambi i campi a zero
Anno accademico 2010-2011
include <stdio.h>
define ERR_FLAG 1
define EOF_FLAG 2
char stream_stat(fp)
FILE *fp;
{
/* se nessun campo booleano è alterato,
* stat vale 0; se il solo campo di errore
* è alterato, stat vale 1; se il solo
* campo di fine file è alterato, stat
* vale 2; se sono alterati entrambi, stat
* vale 3
*/
char stat = 0;
if (ferror(fp))
stat |= ERR_FLAG;
if (feof(fp))
stat |= EOF_FLAG;
clearerr(fp);
return stat;
}
14
Apertura e chiusura di file  1
• Prima di poter accedere al contenuto di un file, è necessario aprirlo
tramite la funzione fopen(), che prevede due parametri: il nome
del file e la modalità di accesso
• Esistono due insiemi di modalità di accesso, per i flussi testuali e
per i flussi binari
“r”
Apre un file testuale esistente in lettura, posizionandosi all’inizio del file; se il file
non esiste, la funzione ritornerà il codice di errore NULL
“w”
Crea un nuovo file testuale e lo apre in scrittura, posizionandosi all’inizio del file; se
il file esiste, i dati precedenti vengono eliminati
“a”
Apre un file testuale esistente in modalità append ; la scrittura può avvenire solo
alla fine del file; se il file non esiste verrà creato automaticamente, in caso
contrario il contenuto del file preesistente verrà mantenuto
“r”
Apre un file testuale esistente in lettura e scrittura, posizionandosi all’inizio del file;
se il file non esiste, la funzione ritornerà il codice di errore NULL
“w”
Crea un nuovo file testuale e lo apre in lettura e scrittura
“a”
Apre un file testuale esistente o ne apre uno nuovo in modalità append; la lettura
può avvenire in una posizione qualsiasi del file, la scrittura solo alla fine
Anno accademico 2010-2011
15
Apertura e chiusura di file  2
• Le modalità binarie differiscono per l’aggiunta di una b (es.,
rb)
• La funzione fopen() restituisce un puntatore a file, utilizzabile
per accedere successivamente al file aperto
Proprietà di file e flussi rispetto alle modalità di apertura della fopen()
r
Il file deve esistere prima dell’apertura
Possibilità di scrittura sul flusso
Possibilità di scrittura solo alla fine
a
*
r
w
a
*
*
Il file preesistente viene reinizializzato
Possibilità di lettura del flusso
w
*
*
*
*
*
*
*
*
*
*
*
*
16
Anno accademico 2010-2011
Apertura e chiusura di file  3
• Esempio: Funzione che apre un file testuale, denominato
test, con accesso in lettura
include <stdio.h>
include <stddef.h>
FILE *open_test()
{
/* restituisce un puntatore ad una struttura FILE */
FILE *fp;
fp  fopen(“test”, “r”);
if (fp  NULL)
fprintf(stderr,“Errore nell’apertura del file test\n”);
return fp;
}
• Note:
 La funzione fprintf() è analoga alla printf(), eccettuato
un parametro aggiuntivo, che identifica il flusso di uscita
 La funzione open_test() è poco flessibile, perché permette
l’apertura del solo file test e soltanto per accessi in lettura
17
Anno accademico 2010-2011
Apertura e chiusura di file  4
include <stdio.h>
include <stddef.h>
FILE *open_file(file_name, access_mode)
char *file_name, *access_mode;
{
FILE *fp;
if ((fp  fopen(file_name, access_mode))  NULL)
fprintf(stderr, “Errore nell’apertura del file %s \
con modalità di accesso %s\n”, file_name, access_mode);
return fp;
}
• La funzione open_file() è equivalente alla fopen(), a
meno della notifica esplicita di errore se il file non può
essere aperto
Anno accademico 2010-2011
18
Apertura e chiusura di file  5
• Per chiudere un file viene utilizzata la funzione fclose(),
con argomento il puntatore alla struttura FILE da chiudere
• La chiusura del file provoca il rilascio della struttura FILE,
per la successiva allocazione ad altri file
• La chiusura del file forza anche la scrittura del contenuto del
buffer associato al flusso
• Dato che tutti i sistemi operativi stabiliscono un numero
massimo di flussi aperti contemporaneamente, è buona
norma chiudere i file quando se ne è conclusa l’elaborazione
• Tutti i flussi aperti vengono comunque chiusi dal sistema
operativo quando il programma termina correttamente (nel
caso di terminazione anomala, il comportamento non è
standardizzato)
19
Anno accademico 2010-2011
Lettura e scrittura di dati
• Su un file aperto è possibile utilizzare il puntatore a file per
svolgere operazioni di lettura e scrittura
• Le operazioni di accesso al file possono essere effettuate su
oggetti di granularità diversa, in particolare a livello di…
 …carattere
 …linea
 …blocco
• Qualsiasi sia la granularità, è impossibile leggere da un flusso
e quindi scrivere sullo stesso flusso senza che fra le due
operazioni venga effettuata una chiamata a fseek(),
rewind() o fflush()
• Le funzioni fseek(), rewind() e fflush() sono le uniche
funzioni di I/O che forzano la scrittura del buffer sul flusso
20
Anno accademico 2010-2011
Lettura e scrittura per caratteri  1
• Esistono due modalità per la lettura/scrittura di caratteri da
un flusso




getc() : macro che
fgetc() : analoga a
putc() : macro che
fputc() : analoga a
legge un carattere da un flusso
getc(), ma realizzata come una funzione
scrive un carattere su un flusso
putc(), ma realizzata come una funzione
• Le macro getc() e putc(), in quanto tali, sono
normalmente molto più veloci delle analoghe funzioni
• Tuttavia, se un parametro attuale contiene operatori che
implicano effetti collaterali, fgetc() ed fputc() sono
preferibili
• Per le altre macro di libreria, lo standard ANSI prevede che gli
argomenti possano comparire una sola volta nel corpo della
macro, per evitare (il sommarsi degli) effetti collaterali
21
Anno accademico 2010-2011
Lettura e scrittura per caratteri  2
• Esempio: Funzione che copia il
contenuto di un file in un altro
• Note:
Entrambi i file vengono acceduti
in modalità binaria
 La macro getc() legge il
prossimo carattere dal flusso
specificato e sposta l’indicatore
di posizione del file avanti di un
elemento ad ogni chiamata
 In modalità binaria, non è
possibile interpretare il valore di
ritorno della getc() per decretare la fine del file: feof()
invece non presenta ambiguità

include <stdio.h>
include <stddef.h>
define FAIL 0
define SUCCESS 1
int copy_file(infile, outfile)
char *infile, *outfile;
{
FILE *fp1, *fp2;
if ((fp1  fopen(infile, “rb”))  NULL)
return FAIL;
if ((fp2  fopen(outfile, “wb”))  NULL)
{
fclose(fp1);
return FAIL;
}
while (!feof(fp1))
putc(getc(fp1), fp2);
fclose(fp1);
fclose(fp2);
return SUCCESS;
}
Anno accademico 2010-2011
22
Lettura e scrittura per linee  1
• Esistono due funzioni di I/O orientate alle linee, fgets() ed
fputs()
• Il prototipo per la funzione fgets() è
char *fgets(char *s, int n, FILE *stream);
Gli argomenti hanno il seguente significato:
: puntatore al primo elemento dell’array in cui vengono
memorizzati i caratteri letti
 n
: numero massimo dei caratteri da leggere
 stream : puntatore al flusso da cui leggere
 s
• La funzione fgets() legge caratteri fino ad un newline, la
fine del file o il numero massimo specificato di caratteri,
inserendo automaticamente un carattere \0 dopo l’ultimo
carattere scritto nell’array; restituisce NULL se incontra la fine
del file, altrimenti restituisce il primo argomento
23
Anno accademico 2010-2011
Lettura e scrittura per linee  2
• La funzione fputs() scrive l’array identificato dal primo
argomento nel flusso identificato dal secondo argomento
• La differenza fondamentale fra gets() (che legge da
stdin) ed fgets() è che la seconda inserisce nell’array
(prima del \0 finale) anche il carattere di newline che
delimita la linea
• Inoltre fgets() permette la specifica del numero massimo
dei caratteri da leggere, mentre gets() procede sempre
fino ad un terminatore (newline o EOF)
24
Anno accademico 2010-2011
Lettura e scrittura per linee  3
● Note:
Il file è aperto in modalità testuale per accedere ai dati a livello di
linea, altrimenti fgets() potrebbe operare in modo scorretto,
cercando caratteri di newline non
presenti nel file (il terminatore di
linea può essere diverso per sistemi operativi diversi)
 fgets(), invece, si “adegua” alle
caratteristiche del sistema operativo specifico
 La funzione copy_file() per linee è più lenta della versione per
caratteri, poiché fgets() ed
fputs() sono realizzate per
mezzo di fgetc() ed fputc()
(meno efficienti delle analoghe
macro)

Anno accademico 2010-2011
include <stdio.h>
include <stddef.h>
define FAIL 0
define SUCCESS 1
define LINESIZE 100
int copy_file(infile, outfile)
char *infile, *outfile;
{
FILE *fp1, *fp2;
char line[LINESIZE];
if ((fp1  fopen(infile, “r”))  NULL)
return FAIL;
if ((fp2  fopen(outfile, “w”))  NULL)
{
fclose(fp1);
return FAIL;
}
while (fgets(line,LINESIZE1,fp1) ! NULL)
fputs(line, fp2);
fclose(fp1);
fclose(fp2);
return SUCCESS;
}
25
Lettura e scrittura per blocchi  1
• Un blocco può essere immaginato come un array: quando si
legge o si scrive un blocco è necessario specificare il numero di
elementi del blocco e la dimensione di ognuno di essi
• Le due funzioni orientate alla gestione dei blocchi sono
fread() e fwrite()
• Il prototipo per la funzione fread() è
int fread(void *ptr,int size,int nmemb,FILE *stream);
• Gli argomenti hanno il seguente significato:
: puntatore ad un array in cui vengono memorizzati i dati
 size : dimensione di ogni elemento dell’array
 nmemb : numero di elementi da leggere
 stream: puntatore a file
 ptr
26
Anno accademico 2010-2011
Lettura e scrittura per blocchi  2
• La funzione fread() restituisce il numero di elementi
effettivamente letti, che dovrebbe coincidere con il terzo
argomento, a meno di errori o di condizioni di fine file
• La funzione fwrite() ha gli stessi argomenti, ma scrive
nel flusso gli elementi contenuti nell’array
• La funzione copy_file() può essere realizzata anche con
granularità di blocco:
 La condizione di fine file è controllata confrontando il numero
degli elementi letti, restituito da fread(), con il valore
specificato nella lista degli argomenti: se sono diversi si ha
una condizione di fine file o di errore
 La funzione ferror() viene utilizzata per stabilire quale
condizione si è verificata
27
Anno accademico 2010-2011
Lettura e scrittura per blocchi  3
include <stdio.h>
include <stddef.h>
define FAIL 0
define SUCCESS 1
define BLOCKSIZE 512
typedef char DATA;
int copy_file(infile, outfile)
char *infile, *outfile;
while ((num_readfread(block,sizeof(DATA),
BLOCKSIZE,fp1)) BLOCKSIZE)
fwrite(block,sizeof(DATA),num_read,fp2);
fwrite(block,sizeof(DATA),num_read,fp2);
if (ferror(fp1))
{
printf(“Errore in lettura del \
file %s\n”,infile);
fclose(fp1);
fclose(fp2);
return FAIL;
}
fclose(fp1);
fclose(fp2);
return SUCCESS;
{
FILE *fp1, *fp2;
DATA block[BLOCKSIZE];
int num_read;
if ((fp1  fopen(infile, “rb”))  NULL)
{
printf(“Errore nell’apertura del file %s \
in input\n”, infile);
return FAIL;
}
if ((fp2  fopen(outfile, “wb”))  NULL)
{
printf(“Errore nell’apertura del file %s \
in output\n”, outfile);
fclose(fp1);
return FAIL;
}
Anno accademico 2010-2011
}
28
La selezione di un metodo di I/O  1
• Le macro putc() e getc() sono le più veloci, ma la
maggior parte dei sistemi operativi è in grado di realizzare
operazioni di I/O su blocchi ancora più efficienti (ad es.,
read() e write() in UNIX)
<stdio.h>
• Talvolta occorre privilegiare include
include <stddef.h>
la semplicità all’efficienza: define MAX_LINE_SIZE 120
fgets() e fputs(), ad int lines_in_file(fp)
FILE *fp;
esempio, sono lente, ma {
char buf[MAX_LINE_SIZE];
particolarmente adatte nei
int line_num  0;
casi in cui sia necessario
rewind(fp); /* sposta l’indicatore di
posizione all’inizio
analizzare linee
del file */
while (fgets(buf,MAX_LINE_SIZE,fp)! NULL)
line_num;
return line_num;
Funzione che conta il
numero di linee di un file
}
Anno accademico 2010-2011
29
La selezione di un metodo di I/O  2
• Ultimo, ma non meno importante, fattore da considerare
nella scelta di un metodo di I/O è la portabilità, fondamentale non tanto nella scelta del tipo di I/O (granularità a
caratteri, linee o blocchi), ma nella scelta della modalità
testo o binaria
 Se il file contiene dati testuali (codice sorgente o documenti),
la modalità testo e l’accesso per linee sono da privilegiare
 Se i dati sono numerici e non sono strutturati per linee, è
preferibile la modalità binaria, con accesso per caratteri o per
blocchi (codice eseguibile)
30
Anno accademico 2010-2011
I/O non bufferizzato  1
• Le librerie di runtime del C consentono di modificare la
dimensione del buffer: tale possibilità deve essere utilizzata
con attenzione, dato che la dimensione del buffer dovrebbe
essere “ottima” per il particolare sistema operativo
• Talvolta, è tuttavia necessario eliminare completamente la
bufferizzazione, tipicamente quando si vogliono elaborare
immediatamente i dati di input
• Per eliminare la bufferizzazione ci si può avvalere delle
funzioni setbuf() e setvbuf()
• La funzione setbuf() richiede due parametri: un puntatore
a file, ed un puntatore ad un array di caratteri da utilizzare
come nuovo buffer; se tale puntatore è nullo, la
bufferizzazione viene eliminata; setbuf() non restituisce
valori
setbuf(stdin,NULL);
31
Anno accademico 2010-2011
I/O non bufferizzato  2
• La funzione setvbuf() richiede due parametri aggiuntivi,
che permettono di specificare la tipologia di bufferizzazione
(per linee, per blocchi, o assente) e la dimensione dell’array
da utilizzare come buffer
• La tipologia di bufferizzazione va specificata mediante uno
dei tre simboli definiti in stdio.h:
: bufferizzazione per blocchi
 _IOLBF : bufferizzazione per linee
 _IONBF : bufferizzazione assente
 _IOFBF
• La funzione restituisce un valore diverso da zero se
completata correttamente, zero se non è in grado di
soddisfare la richiesta
setvbuf(stdin,NULL,_IONBF,0);
32
Anno accademico 2010-2011
L’accesso diretto a file  1
• In C, le funzioni per l’accesso diretto a file sono fseek() e
ftell()
• La funzione fseek() sposta l’indicatore di posizione del file a
un carattere specificato nel flusso
• Il prototipo della fseek() è
int fseek(FILE *stream,long int offset,int whence)
dove:



stream : puntatore a file
offset : numero di caratteri di spostamento
whence : posizione di partenza da cui calcolare lo spostamento



SEEK_SET : inizio del file
SEEK_CUR : posizione corrente dell’indicatore
SEEK_END : fine del file
• L’argomento whence può assumere uno dei tre seguenti
valori, definiti in stdio.h
Anno accademico 2010-2011
33
L’accesso diretto a file  2
• Esempio: L’istruzione
stat  fseek(fp,10,SEEK_SET);
sposta l’indicatore di posizione del file al carattere 10 del
flusso (l’undicesimo), che sarà il prossimo elemento letto o
scritto
• La fseek() restituisce zero se la richiesta è corretta, un
valore diverso da zero altrimenti
• Esempio: L’istruzione
stat  fseek(fp,1,SEEK_END);
non è lecita se fp è aperto in sola lettura, perché sposta
l’indicatore oltre la fine del file
• Per flussi binari, lo spostamento può essere un qualsiasi
numero intero che non sposti l’indicatore al di fuori del file;
per flussi testuali, deve essere zero o un valore restituito
dalla ftell()
Anno accademico 2010-2011
34
L’accesso diretto a file  3
• La funzione ftell() richiede, come unico argomento, un
puntatore a file e restituisce la posizione corrente dell’indicatore di posizione nel file
• La posizione restituita da ftell() si intende relativa
all’inizio del file…
 …per flussi binari rappresenta il numero di caratteri dall’inizio
del file alla posizione corrente
 …per flussi testuali rappresenta un valore dipendente
dall’implementazione, significativo solo se utilizzato come
parametro per la fseek()
cur_pos  ftell(fp);
if (search(string)  FAIL)
fseek(fp,cur_pos,SEEK_set);
Se la ricerca di una certa stringa nel
file fallisce, l’indicatore di posizione
nel file viene riportato al valore
originale
35
Anno accademico 2010-2011
Esempio: dimensione del file
/* Determinazione del numero di caratteri di un file con fseek e ftell */
include <stdio.h>
main(int argc, char **argv)
{
FILE *fp;
long n;
if (argc<2)
printf(“File non specificato\n”);
else
{
fpfopen(argv[1], “rb”);
/* apertura del file */
if (fp ! NULL)
{
fseek(fp, 0, SEEK_END);
/* puntatore alla fine del file */
nftell(fp);
/* lettura posizione del puntatore */
fclose(fp);
printf(“Dimensione del file %ld\n”, n);
}
else
printf(“Errore: il file %s non esiste”, argv[1]);
}
}
36
Anno accademico 2010-2011
Scarica