File di testo
Indice
Introduzione
File: sequenza di byte a cui il Sistema Operativo dà un nome ed una collocazione sul dispositivo di memoria di massa
classificazione per accesso
File ad accesso sequenziale
- hanno record di lunghezza variabile
- per accedere al record numero n bisogna leggere tutti i precedenti n -1 record per determinare il byte da dove esso inizia
File ad accesso diretto (casuale, random)
- hanno record di lunghezza fissa
- la lunghezza L del record viene decisa dal programmatore file per file
- per accedere al record numero n si determina il byte da dove esso inizia con il calcolo: n *L
classificazione per contenuto
File di testo
- Sono sequenze di caratteri organizzati in righe
- Ogni riga è terminata da un ritorno a capo, l’ultima può non averlo
- Le funzioni di I/O per stringhe e caratteri gestiscono il carattere '\n' come generico ritorno a capo
File binari
- Sono sequenze “grezze” di byte
- nessun carattere né sequenza di caratteri viene interpretata in modo speciale (fine riga, '\0', ecc.)
gestione file
Dal punto di vista del linguaggio C, non c’è differenza tra leggere da un file o dalla tastiera, o tra scrivere su un file o sul video. In ogni caso abbiamo due flussi (stream) di caratteri.
Le funzioni di I/O per i file richiedono che sia indicato lo stream da utilizzare, mentre quelle per video e tastiera utilizzano implicitamente degli stream associati a questi dispositivi
il tipo FILE
Per utilizzare un file è necessario che il sistema legga dal disco e tenga in memoria le sue caratteristiche (lunghezza, ecc.)
Queste informazioni sono memorizzate in una struttura dati composta (struct) che ha tipo FILE
Ogni accesso a un file avviene attraverso una variabile che si riferisce alla struttura FILE associata a quel file, questa variabile è di tipo puntatore ed è detta file pointer.
FILE *variabile; FILE *fp;
La struttura dati FILE contiene tra le informazioni relative al file il cosiddetto offset
(o file position pointer ) che memorizza il punto in cui la lettura o scrittura è arrivata
(indica la posizione del prossimo byte da leggere o da scrivere, calcolata rispetto al primo byte del file che ha offset=0)
Apertura di un file
Per utilizzare un file bisogna richiederne l’accesso al Sistema Operativo indicando anche per quale scopo (lettura o scrittura), questa operazione è detta apertura del file
La funzione fopen apre un file
FILE *fp = fopen(nome, modo);
I parametri della funzione sono
- nome
- una stringa (costante o variabile) contenente il nome del file e l’eventuale percorso
- modo
- è una stringa indicante la modalità di apertura del file (lettura o scrittura)
fopen restituisce NULL se non riesce ad aprire il file, altrimenti restituisce il puntatore alla struttura FILE associata al file
Bisogna verificare sempre il valore di fopen
#include <stdio.h> #include <stdlib.h> #define NOME_FILE "prova.txt" int main() { FILE* fp; int i = 42; fp = fopen(NOME_FILE, "w"); if (fp != NULL) { fprintf(fp, "SONO UNA CAROTA %d\n", i); fclose(fp); } else { printf("ERRORE SCRITTURA FILE\n"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
Chiusura di un file
Informa il Sistema Operativo che è terminato l’utilizzo di un certo file.
Funzione da usare:
fclose(fp);
Libera le risorse di sistema legate a quel file
- È automatica al termine del programma (ma è buona norma chiuderlo non appena non serve più, in particolare se file di output)
- Nel caso di file di output, prima della chiusura effettua automaticamente il flush dei buffer (vedere più avanti)
Lettura di un file
lettura riga per riga
Posso leggere un file una riga per volta facendo uso della funzione fgets e sfruttando il fatto che
la funzione restituisce NULL quando non è più in grado di leggere dal file.
void leggo_file_una_riga_per_volta(FILE *fp) { char s[LUNGHEZZA_RIGA]; // associo lunghezza massima di una riga ad 80 caratteri while(fgets(s, LUNGHEZZA_RIGA, fp) != NULL) { printf("Ho letto questa riga: "); printf("%s", s); } rewind(fp); // torno ad inizio file }
lettura file carattere per carattere
In caso abbia la necessità di leggere un carattere alla volta devo fare uso della funzione fgetc
void leggo_file_un_carattere_alla_volta(FILE *fp) { int val1; while((val1 = fgetc(fp)) != EOF) { printf("Ho letto il carattere -%c-\n", val1); } rewind(fp); // torno ad inizio file }
lettura formattata
Le funzioni di lettura/scrittura su file sono varianti di quelle già viste per il terminale
int i = fscanf(fp, "%d%d%d", &val1, &val2, &val3); // VARIANTE sscanf() legge da una stringa (es: parsing di una riga) // EOF se il file non e' leggibile perche' sono arrivato in fondo // i == 0 se riesco a leggere il file ma non ci sono NUMERI // i == 1 se riesco a leggere un numero // i == 2 se ne riesco a leggere 2 if (i == EOF) { printf("IL FILE E' FINITO\n"); } else { printf("i vale %d\n", i); printf("val1 vale %d\n", val1); printf("val2 vale %d\n", val2); printf("val3 vale %d\n", val3); }
scrittura formattata
Le funzioni di lettura/scrittura su file sono varianti di quelle già viste per il terminale
Per scrivere una stringa in un file e' possibile usare quindi la funzione fprintf
fprintf(fp, "%s", riga); fprintf(fp, "%d - %d - %d\n", var1, var2, var3);
gestione errori
Gestione degli errori
Le seguenti funzioni richiedono <stdio.h>
ferror(fp)dà un valore intero non nullo se si è verificato unEOFsullo stream fpferror(fp)dà un valore intero non nullo se si è verificato un errore (non EOF) sullo stream fpclearerr(fp)cancella le indicazioni di errori e di EOF relativi a fp
gestione input formattato
Se la lettura di valori mediante fscanf produce un valore minore di quello atteso:
- se feof è vera: raggiunta fine file
- se ferror è vera: errore di lettura
altrimenti c’è un errore sul’la corrispondenza del
tipo di dati (es. la stringa di formato ha un %d e il dato in input non è numerico)
if (fscanf(fp, "%d", &a) !=1) { if (feof(fp)) // fine del file // esci / segnala else if (ferror(fp)) // errore nel file // esci o segnala else // matching failure ( ho letto un intero ma c'era un stringa) fscanf(fp, "%*[^\n]"); // es. svuota la riga }
Quando si verifica un errore, le funzioni che lavorano sui file (e altre) assegnano alla variabile errno
(richiede <errno.h>), un valore intero che lo identifica
Per visualizzare il messaggio di errore corrispondente al valore di errno si usa la funzione
perror(stringa) che visualizza stringa e un messaggio di errore corrispondente al valore
in errno (serve includere <stdio.h> e <errno.h>)