HOWTO · C
Leggi file linea per linea utilizzando fscanf in C
In questo articolo viene illustrato come leggere il file linea per linea utilizzando fscanf in C
In questa pagina
fscanf legge dati formattati da uno stream FILE. Una scanset può raccogliere i caratteri fino a una nuova riga, ma, a differenza di una funzione dedicata alla lettura delle righe, richiede una gestione esplicita delle righe vuote e dei blocchi di lunghezza limitata. Per i normali file di testo, di solito fgets è la scelta più semplice; usa fscanf quando il formato di input richiede conversioni.
Leggere un file riga per riga con fscanf in C
Questo esempio completo crea un file temporaneo, vi scrive due righe di esempio e legge lo stream con una scanset limitata al buffer di destinazione da 16 byte. Il programma scrive due righe di esempio in uno stream temporaneo e le stampa man mano che le legge. Le stringhe mostrate dal blocco di codice restano in inglese.
#include <stdio.h>
int main(void) {
FILE *file = tmpfile();
char line[16];
if (file == NULL) {
return 1;
}
if (fputs("First line.\nSecond line.\n", file) == EOF || ferror(file)) {
fclose(file);
return 1;
}
if (fflush(file) == EOF || ferror(file)) {
fclose(file);
return 1;
}
rewind(file);
for (;;) {
int result = fscanf(file, "%15[^\n]", line);
if (result == 1) {
int ch;
puts(line);
ch = fgetc(file);
if (ch == '\n') {
continue;
}
if (ch == EOF) {
break;
}
ungetc(ch, file);
while ((ch = fgetc(file)) != '\n' && ch != EOF) {
}
if (ch == EOF) {
break;
}
continue;
}
if (result == EOF) {
break;
}
if (fgetc(file) == '\n') {
puts("");
}
}
fclose(file);
return 0;
}
Una larghezza di 15 lascia spazio per il carattere null terminatore in line. Dopo ogni conversione della scanset riuscita, il programma controlla la nuova riga. Se una riga supera la capacità del buffer, ne scarta il resto prima di leggere la riga successiva: così l’uso della memoria rimane limitato, ma la riga lunga non viene conservata per intero. Se, in corrispondenza di una nuova riga, la scanset non trova alcun carattere, il ciclo consuma la nuova riga e stampa una riga vuota, invece di riprovare senza avanzare. Nel codice di produzione, dopo la fine dell’input, è opportuno controllare anche ferror(file) per distinguere un errore di lettura dalla normale fine del file.
Leggere token separati da spazi con fscanf
Per analizzare i token, %255s legge un token senza spazi bianchi nel buffer char token[256]. La larghezza evita di scrivere oltre i limiti dell’array e %s ignora gli spazi bianchi iniziali, fermandosi al successivo carattere di spazio bianco. Il ciclo dovrebbe continuare solo se fscanf(file, "%255s", token) == 1; controllare soltanto EOF può causare ripetizioni infinite quando una conversione fallisce senza consumare input. Questo approccio usa intenzionalmente spazi, tabulazioni e nuove righe come separatori, quindi non conserva i confini delle righe originali. Per i campi numerici, usa gli specificatori di conversione corrispondenti e controlla quante assegnazioni sono riuscite.
Usare fgets per leggere le righe in modo affidabile
Quando ogni record di testo corrisponde a una riga, in genere fgets(buffer, sizeof buffer, file) è più semplice da gestire. Legge al massimo un carattere in meno della capacità del buffer e conserva la nuova riga se entra nel buffer. Prima di usare il buffer, controlla il valore restituito. Se il buffer si riempie senza contenere una nuova riga, la riga logica continua nello stream: leggi altri blocchi oppure scarta il resto, in base all’esigenza. L’ultima riga può terminare con EOF senza una nuova riga finale. fgets gestisce naturalmente anche le righe vuote, perché può restituire un buffer che contiene solo il carattere di nuova riga.
Scegli fscanf quando ti servono campi formattati o token separati da spazi bianchi. Scegli fgets quando è importante conservare i confini delle righe; se necessario, analizza poi separatamente la stringa ottenuta. Controlla sempre che fopen abbia esito positivo, verifica i risultati delle conversioni e chiudi gli stream dopo l’uso.