6 - FILES
versione 11/02/2013
 
SEQUENZE DI ESCAPE

Le sequenze di escape semplici possono essere uno dei seguenti valori:

Sequenze di escape
code significato
\n new line (o line feed - in ascii 10)
\r carriage return (in ascii 13)
\t tabulazione (in ascii 9)
\v vertical tab (in ascii 11)
\b backspace (in ascii 8)
\f form feed (in ascii 12)
\b avviso (in ascii 7)
\0 carattere nullo (in ascii 0)
\\ barra rovesciata (in ascii 92)

LE STRINGHE

strcmp()

Confronta due stringhe. Richiede l'header <string.h>.

int strcmp(const char *s1, const char *s2);

dove s1 e s2 sono le stringhe da confrontare. Questa funzione inizia a confrontare il primo carattere delle 2 stringhe e continua finché non incontra due caratteri diversi oppure incontra il carattere '\0'. Questa funzione effettua un confronto binario tra i caratteri.
La funzione strcmp() ritorna un intero minore, uguale o maggiore di 0 a seconda che s1 sia rispettivamente minore, uguale o maggiore di s2.

strncmp()

La funzione strncmp() limita il confronto fra le due stringhe s1 e s2 al piu' a n caratteri. Richiede l'header <string.h>.

int strncmp(const char *s1, const char *s2, size_t n);

dove s1 e s2 sono le stringhe da confrontare. Questa funzione inizia a confrontare il primo carattere delle 2 stringhe e continua finché:

- non incontra due caratteri diversi
- incontra il carattere '\0'.
- abbia confrontato n caratteri.

Questa funzione effettua un confronto binario tra i caratteri. La funzione strcnmp() ritorna un intero minore, uguale o maggiore di 0 a seconda che i primi n caratteri di s1 sia rispettivamente minore, uguale o maggiore dei corrispondenti caratteri in s2.

strlen()

La funzione strlen() calcola la lunghezza della stringa s, (inteso come il numero di caratteri dell'array puntato da s) escluso il terminatore '\0'. Richiede l'header <string.h>. La sua sintassi è:

size_t strlen(const char *s);

dove size_t indica un unsigned int. La funzione strlen() ritorna il numero di caratteri in s. La lunghezza della stringa è determinata dalla posizione del carattere nullo di terminazione.

strstr()

La sintassi della funzione strstr() è:

const char * strstr ( const char *str, const char *cercata );
char * strstr ( char *str, const char *cercata );

Restituisce il puntatore alla prima occorrenza della stringa cercata dentro str. Restituisce un puntatore NULL se cercata non è presente in str. Richiede l'header <string.h>.

I FILES

Il linguaggio C non contiene alcuna istruzione di Input/Output. Tali operazioni vengono svolte mediante chiamate a funzioni definite nella libreria standard contenute nel file stdio.h. Tali funzioni rendono possibile la lettura/scrittura in modo indipendente dalle caratteristiche proprie dei dispositivi di Input/Output. Le stesse funzioni possono essere utilizzate, ad esempio, sia per leggere un valore dalla tastiera sia per leggere un valore da un dispositivo di memoria di massa. Lo stesso vale per le funzioni di scrittura: le stesse operazioni possono essere utilizzate sia per la visualizzazione sullo schermo sia per scrivere un valore su un disco o una stampante. Ciò è possibile poichè il sistema di I/O C è caratterizzato da un’interfaccia indipendente dal dispositivo effettivo che si interpone tra il programmatore e il dispositivo. Tale interfaccia è chiamata flusso, mentre il dispositivo effettivo è chiamato file.

Il sistema di I/O C associa ad ogni dispositivo fisico un dispositivo logico chiamato flusso. Poichè tutti i flussi si comportano alla stessa maniera, possono essere utilizzate le stesse funzioni per la loro gestione. Esistono due tipi di flussi: flussi binari e di testo.
Un flusso binario è formato da una sequenza di byte con una corrispondenza uno ad uno con i byte presenti sul dispositivo fisico.
Un flusso di testo è una sequenza di caratteri generalmente suddivisa in linee terminate da un carattere di newline.

Un File è un qualsiasi dispositivo, da un disco a un monitor a una stampante. Per associare un flusso a un file è necessario un’operazione di apertura.
Una volta aperto un file sarà possibile scambiare informazioni tra il file e il programma. Per eliminare l’associazione tra flusso e file è necessaria un’operazione di chiusura.
Nel caso un file aperto in scrittura, l’eventuale contenuto del flusso viene scritto sul dispositivo fisico.

Ogni flusso ha associato una struttura chiamata FILE contenente i seguenti campi:

- Modalità di utilizzo del file (lettura, scrittura o lettura e scrittura);
- Posizione corrente su file (indicante il prossimo byte da leggere o scrivere su file);
- Un indicatore di errore di lettura/scrittura;
- Un indicatore di end-of-file, indicante il raggiungimento della fine del file.

Ecco una possibile struttura FILE:

typedef struct 
{  
	char *fpos; /* Current position of file pointer (absolute address) */
	void *base; /* Pointer to the base of the file */
	unsigned short handle; /* File handle */
	FileFlags flags; /* Flags (see FileFlags) */
	short unget; /* 1-byte buffer for ungetc (b15=1 if non-empty) */
	unsigned long alloc; /* Number of currently allocated bytes for the file */
	unsigned short buffincrement; /* Number of bytes allocated at once */
} FILE;
enum FileFlags 
{
	_F_READ = 0x0001, 
	_F_WRIT = 0x0002, 
	_F_RDWR = 0x0003, 
	_F_ERR = 0x0010, 
	_F_EOF = 0x0020, 
	_F_BIN = 0x0040
};
FILE è la principale struttura di controllo per gli stream (flussi o file). L'esatta struttura è in realtà strettamente legata alla piattaforma su cui gira il programma. Per evitare problemi un programma ben scritto non dovrebbe mai andare a leggere direttamente o modificare i campi interni di questa struttura.

In modo predefinito, ci sono sempre tre "file" aperti:
- lo stdin (la tastiera),
- lo stdout (lo schermo)
- lo stderr (la visualizzazione a schermo dei messaggi d'errore).


fopen()

Ogni operazione di apertura a file restituisce un puntatore ad una variabile di tipo FILE. Per potere leggere o scrivere i file è necessario usare delle variabili di tipo puntatore a FILE, dichiarate nel seguente modo:

FILE *fp;

L’apertura di un file viene realizzata mediante la funzione fopen() che ha il seguente prototipo:

FILE * fopen ( const char * nomefile, const char * mode );

dove nomefile è una stringa di caratteri indicante il nome del file da aprire e mode è la modalità che indica il modo in cui il file deve essere aperto. Il parametro mode assume i seguenti valori:

Modalità file testuali
mode significato
r Apre un file di testo in lettura
w Crea un file di testo in scrittura
a Apre un file di testo in modalità append
r+ Apre un file di testo in lettura/scrittura
w+ Crea un file di testo in lettura/scrittura
a+ Crea o apre un file di testo in modalità append per lettura/scrittura

Modalità file binari
mode significato
rb Apre un file binario in lettura
wb Crea un file di binario in scrittura
ab Apre un file di binario in modalità append
r+b Apre un file di binario in lettura/scrittura
w+b Crea un file di binario in lettura/scrittura (azzera prima il file)
a+b Crea o apre un file di binario in modalità append per lettura/scrittura

Se si verifica un errore in apertura del file, la fopen() restituisce un puntatore nullo (NULL).

fclose()

La chiusura di un file viene realizzata mediante la funzione fclose avente il seguente prototipo:

int fclose ( FILE *fp );

dove fp è il puntatore restituito dalla fopen(). Se lo stream viene chiuso correttamente restituisce zero altrimenti in caso di errore EOF.

feof()

La funzione feof() restituisce un valore logico vero nel caso in cui è raggiunta la fine del file e zero in tutti gli altri casi. Il prototipo della feof è il seguente:

int feof ( FILE *fp );

dove fp è il puntatore restituito dalla fopen().

fprintf()

La funzione fprintf() è utilizzata per la scrittura su file testuali. Il suo comportamento è lo stesso della funzione printf(). Il suo prototipo è il seguente:

int fprintf ( FILE *fp, const char *formato, ... );

dove fp è il puntatore restituito dalla fopen(). La funzione restituisce il numero di caratteri scritti. Se si verifica un errore di scrittura la funzione restituisce un numero negativo corrispondente all'errore che viene rilevato con la funzione ferror(). La funzione printf(...) equivale a fprintf(stdout,...) dove stdout è il descrittore standard associato allo schermo;

fgetc()

Acquisisce il carattere successivo (un unsigned char) dallo stream puntato da fp e sposta in avanti di uno l'indice di posizione dello stream. La sua sintassi è la seguente:

int fgetc(FILE *fp);

Se ha successo la funzione restituisce il carattere letto. Se si arriva alla fine del file restituisce il carattere EOF e l'indicatore restituito da feof() viene posto a true. Se si verifica un errore viene settato l'indicatore di errore per lo stream (ferror) e viene restituito il carattere EOF.
 
soluzione senza feof() soluzione con feof()
#include <stdio.h>
#include <stdlib.h> // richiesto da system("pause")
int main ()
{
    FILE *fp;
    int ch;
    fp=fopen ("lab1.txt","r");
    if (fp==NULL) 
        perror ("Errore nell'apertura dei files!");
    else
    {
        while ((ch=fgetc(fp))!=EOF)
            printf("%c",ch);
        fclose (fp);
    }
    system("pause");
    return 0;
}
#include <stdio.h>
#include <stdlib.h> // richiesto da system("pause")
int main ()
{
    FILE *fp;
    int ch;
    fp=fopen ("lab1.txt","r");
    if (fp==NULL) 
        perror ("Errore nell'apertura dei files!");
    else
    {
        while (!feof(fp))
        {
             ch=fgetc(fp);
             printf("%c",ch);
        }
        fclose (fp);
    }
    system("pause");
    return 0;}

fgets()

La funzione fgets() è utilizzata per la lettura di file testuali. Legge una riga dallo stream specificato e lo pone nella stringa puntata da str. Si ferma:
- dopo (n-1) caratteri (tiene conto quindi dell'aggiunta del '\0' finale),
- oppure dopo il carattere invio (a-capo - eol - ascii(13)+ascii(10) in dos),
- oppure quando incontra la fine del file (EOF).

Il carattere di invio viene copiato nella stringa. Un carattere null ('\0') viene aggiunto in fondo alla stringa come simbolo di terminazione. La sua sintassi è la seguente:

char *fgets(char *str, int n, FILE *fp);

dove fp è il puntatore restituito dalla fopen(). Se ha successo viene restituito un puntatore alla stringa che contiene i dati letti. Se c'è errore viene ritornato un puntatore a null. Se viene incontrato un EOF l'indicatore restituito da feof viene posto a true.
Si osservi che fgets è leggermente diverso da gets {char *gets (char *str)}: non solo per la presenza del puntatore a file come argomento ma anche perché consente di indicare il massimo numero di caratteri leggibili ed inoltre include il carattere eol all'interno della stringa.

fputc()

La funzione fputc() scrive un carattere in un file. La sintassi è la seguente:

int fputc(int char, FILE *stream);

Il parametro c viene scritto sullo stream puntato da fp eseguendo un cast a unsigned char. Ritorna il carattere scritto se la funzione ha successo, altrimenti EOF in caso di errore (chiaramente viene settato 'indicatore di errore). La funzione putc() equivale a fputc() eccetto che potrebbe essere implementata come macro e valutare stream piu' di una volta.


fread()

La funzione fread() è utilizzata per la lettura dei file binari (legge una sequenza di byte). Il suo prototipo è il seguente:

// size_t è unsigned int;
size_t fread( void *ptr, size_t dimens, size_t count, FILE *fp );

La funzione fread() legge dallo stream fp count elementi, ciascuno di dimensione dimens. Gli elementi letti vengono immagazzinati nel buffer puntato da ptr che deve essere di dimensioni adeguate (dimens*count). La funzione fread() ritorna il numero di elementi letti. In caso di errore o di raggiungimento di EOF viene restituito un numero che è minore di count. E' necessario chiamare le funzioni feof() e/o ferror() in caso venga restituito un numero minore di count. L'indicatore di posizione dello stream viene fatto avanzare di un numero di byte pari a quelli letti.

fwrite()

La funzione fwrite() è utilizzata per la scrittura di file binari. Il suo prototipo è il seguente:

// size_t è unsigned int;
size_t fwrite(const void *ptr, size_t dimens, size_t count, FILE *fp);

La funzione fwrite() scrive sullo stream fp count elementi, ciascuno di dimensione dimens. La funzione fwrite() ritorna il numero di elementi scritti. In caso di errore viene restituito un numero minore di count.  E' necessario chiamare le funzioni feof() e/o ferror() in caso venga restituito un numero minore di count. L'indicatore di posizione dello stream viene fatto avanzare di un numero di byte pari a quelli scritti. Il totale di byte scritti è (count*dimens).

fseek()

La funzione fseek() imposta l'indicatore di posizione del file. La prossima operazione di I/O su stream verra' eseguita sulla nuova posizione impostata. La sintassi è:

int fseek ( FILE *fp, long int offset, int dadove );

La posizione e' calcolata aggiungendo offset (che puo' assumere anche valori negativi) a dadove.
Il parametro dadove puo' valere:

- SEEK_SET: per specificare rispetto alla posizione di inizio file,
- SEEK_CUR
: per specificare rispetto alla posizione corrente,
- SEEK_END per specificare rispetto alla fine del file.

In caso di successo, fseek() ritorna 0 e viene eventualmente cancellato l'indicatore di fine file. In caso di fallimento ritorna -1. Se lo stream è aperto in update (read+write), la chiamata a fseek permette di passare dalla modalità lettura a quella di scrittura.
L'istruzione (void)fseek(stream, 0L, SEEK_SET) è funzionalmente equivalente a rewind() (vedere la funzione rewind())

ftell()

La funzione ftell() restituisce la posizione del cursore (indicatore di posizione) del file passato come argomento alla funzione. Tale posizione corrisponde alla distanza in byte del cursore rispetto all'inizio del file stesso. La funzione può essere utilizzata per calcolare la dimensione in byte del file oppure per registrare una posizione a cui occorre ritornare dopo aver eseguito un’operazione di lettura/scrittura.

long int ftell ( FILE *fp );

La funzione può essere utilizzata per calcolare la dimensione in byte del file oppure per ritornare alla posizione precedente rispetto all'ultima operazione di lettura/scrittura.

Calcolo dimensione in byte di un file
#include <stdio.h>
#include <stdlib.h> // richiesto da system("pause")
#include 
#include 
int main ()
{
   FILE *fp;
   long n,nr;
   fp = fopen("lab2.dat", "rb");
   if (fp==NULL) 
      perror ("Errore nell'apertura dei files!"); 
   else
   {
      fseek(fp, 0L, SEEK_END); // vado in fondo
      n = ftell(fp);  // leggo la posizione in byte
      nr=n/sizeof(int);
      printf("Dimens.: %ld byte - %ld record\n",n,nr);
   }
   fclose(fp);
   system("pause");
   return 0;
}

In caso di successo, ftell() ritorna il numero di byte a partire dall'inizio (il primo byte del file corrisponde alla posizione zero). In caso di fallimento ritorna -1L e la macro errno viene impostata ad un valore positivo che identifica il tipo di errore occorso.

rewind()

La funzione rewind() imposta l'indicatore di posizione del file all'inizio dello stesso. La prossima operazione di I/O su stream verra' eseguita all'inizio del file. La sintassi è:

void rewind( FILE *fp );

Funzionalmente coincide con l'istruzione (void)fseek(stream, 0L, SEEK_SET) tranne che per 2 aspetti:

- non restituisce alcun valore per cui non è possibile valutare l'esito positivo dell'esecuzione di tale istruzione
- rewind() resetta l'indicatore di errore()

Link utili

http://www.math.unipd.it/~sperduti/CORSO-C%2B%2B/Strutture.htmm