Rilevazione end-of-file

Il programma di lettura di array da file non contiene nessun meccanismo di rilevazione di errori su file. Per esempio, non si accorge se il file è più corto del dovuto, ossia contiene meno elementi di quelli specificati come primo intero. Inoltre, non contiene nessun controllo sul fatto che il file potrebbe contenere dei caratteri, che quindi non sono interpretabili come interi. A seconda di come è specificato il formato del file da cui leggere, queste situazioni possono venire considerate o meno degli errori da parte di chi ha scritto il file. Per il momento, assumiamo che entrambe le situazioni vanno interpretate come errori.

Il modo in cui le funzioni di accesso a file comunicano un eventuale errore è attraverso il valore di ritorno. Per esempio, errori in apertura del file si rilevano mettendo il valore di ritorno della funzione fopen in una variabile, e controllando il valore di questa variabile. Per le operazioni di lettura da file si usa lo stesso metodo: fscanf è in effetti una funzione che ritorna un valore intero, che indica se ci sono stati o meno degli errori in scrittura. Per controllare se ci sono stati errori, dobbiamo quindi memorizzare il valore di ritorno della funzione fscanf in una variabile, e poi controllare se il valore di questa variabile indica se ci sono stati errori.

Per il momento, diciamo che la funzione fscanf ritorna il valore EOF nel caso in cui si è tentato di leggere qualcosa da un file, ma il file è già finito. In altre parole, se si è letto tutto il contenuto di un file, e si usa fscanf per leggere ancora, questa funzione ritorna il valore EOF. Questo EOF è una macro di cui non ci interessa il valore.

Si noti che EOF è il valore di ritorno della funzione fscanf, e non il valore che viene memorizzato nelle variabili da leggere. In altre parole, se si vuole leggere un intero da file, controllando che non si sia arrivati alla fine del file, occorre controllare se il valore di ritorno di fscanf vale EOF, con un frammento di codice come quello che segue:

    res=fscanf(fd, "%d", &x);
    if( res==EOF ) {
      printf("Non riesco a leggere un intero: il file e' finito\n");
      exit(1);
    }

Le variabili res e x sono entrambe dichiarate come intere. Mentre x contiene il valore che si è letto da file (in caso la cosa sia avvenuta con successo) la variabile res viene usata per memorizzare il valore di ritorno di fscanf, per cui viene usata per controllare che non ci siano stati errori in lettura.

Il seguente programma arrayeof.c legge un vettore da file. Ci si ferma solo nel caso in cui si sia arrivati a leggere cento elementi, oppure quando si cerca di leggere un intero ma il file è terminato. Si noti che, in questo caso, il numero iniziale che indica quanti interi ci sono su file non è necessario. Infatti, il numero di elementi letti viene determinato leggendo via via gli interi da file, incrementando ogni volta il numero di elementi letti fino a che non si arriva alla fine del file.

In questo caso, se si incontra la fine del file, non si deve stampare un messaggio di errore. Infatti, la fine del file indica semplicemente che non c'è altro da leggere, ossia che siamo arrivati all'ultimo elemento del vettore. In questo caso, la fine del file viene usata per indicare quanti elementi da leggere ci sono. Al contrario, nel caso in cui si fosse per esempio specificato che il file deve contenere esattamente cento elementi, allora trovare EOF prima del centesimo elemento sarebbe stato un errore. Si può dire che incontrare la fine di un file durante una operazione di lettura può essere o non essere un errore, a seconda di come è stato specificato il formato del file.

/*
  Legge un array da file, con rilevazione di end-of-file.
*/

#include<stdlib.h>
#include<stdio.h>

int main() {
  int n;
  int vett[100];
  FILE *fd;
  int res;
  int i;

		/* apre il file */
  fd=fopen("arrayeof.txt", "r"); 

		/* verifica errori in apertura */
  if( fd==NULL ) {
    perror("Errore in apertura del file");
    exit(1);
  }

  
		/* legge l'array */
  for(n=0; n<=100-1; n++) {
    res=fscanf(fd, "%d", &vett[n]);
    if( res==EOF )
      break;
  }


		/* stampa l'array */
  for(i=0; i<=n-1; i++)
    printf("%d\n", vett[i]);

		/* chiude il file */
  fclose(fd);

  return 0;
}