Perché ifstream.eof () non restituisce VERO dopo aver letto l'ultima riga di un file?


11

Quando un principiante inizia a leggere ifstreams, il suo istinto è quello di leggere il file usando un ciclo che di solito assomiglia a questo:

while (!ifstream.eof()
{
...
}

Tuttavia, quando ho usato questo codice ho notato che non si è fermato fino a quando non ha letto due volte l'ultima riga del file. I programmatori C ++ notano che questo non è in realtà il modo in cui si dovrebbe leggere un file. Invece, di solito raccomandano a chiunque abbia bisogno di leggere un file di usare un ciclo come questo:

while (ifstream >> someVar)
{
...
}

Perché il primo pezzo di codice non funziona sempre correttamente?


Avrei pensato che ci sarebbe stato un duplicato, ma non riesco a trovarne uno qui. Ci sono molti duplicati su StackOverflow.
David Hammen,

Risposte:


4

Il while (!ifstream.eof())ciclo non funziona, poiché i flussi / file in C e C ++ non prevedono quando hai raggiunto la fine del file, ma indicano piuttosto se hai provato a leggere oltre la fine del file.

Se l'ultima riga del file termina con un carattere newline ( \n), la maggior parte delle azioni di lettura interromperà la lettura quando incontreranno quel carattere e non rileveranno che si tratta dell'ultimo carattere nel file. Alla prossima azione di lettura, può anche essere che siano stati aggiunti più personaggi e che la lettura riesca a estrarli.

Il ciclo che utilizza l'operatore di estrazione del flusso ( while (ifstream >> someVar)) funziona perché il risultato dell'operatore di estrazione del flusso è stato valutato falso se non è stato possibile estrarre un elemento del tipo giusto. Questo succede anche se non ci sono caratteri da leggere.


4

Tuttavia, i programmatori C ++ notano che ciò che accade sempre è che cin.eof () non restituisce "vero" fino a quando non viene letta due volte l'ultima riga.

Non è quello che sta succedendo. Non ha eofbitalcun ruolo nella conversione in un valore booleano ( stream::operator bool(o operator void*nel vecchio c ++)). Sono coinvolti solo badbite failbit.

Supponiamo di leggere un file contenente numeri separati da spazi bianchi. Un loop basato intorno cin.eof()sarà inevitabilmente sbagliato o pieno zeppo di iftest. Non stai leggendo fino a EOF. Stai leggendo i numeri. Quindi fai esprimere al tuo codice quella logica:

while (stream >> some_var) {
    process_value(some_var);
}

Funzionerà se l'ultima riga del file termina con 0 42\no solo 0 42(nessuna nuova riga alla fine dell'ultima riga nel file). Se il file termina con 0 42\n, l'ultima lettura corretta recupererà il valore 42 e leggerà quell'indicatore di fine riga finale. Si noti che il marker EOF non è stato ancora letto. La funzione process_valueviene chiamata con 42. La chiamata successiva all'operatore di estrazione del flusso >> legge l'EOF e poiché non è stato estratto nulla, verranno impostati sia eofbite failbit.

Supponiamo invece che il file termini con 0 42(nessuna nuova riga alla fine dell'ultima riga). L'ultima lettura corretta recupererà il valore 42 che termina sul marker EOF. Presumibilmente si desidera elaborare tale 42. Ecco perché eofbitnon gioca un ruolo nell'operatore di conversione booleana del flusso di input. Alla chiamata successiva all'operatore di estrazione del flusso >>, il macchinario sottostante vede rapidamente che eofbitè già impostato. Ciò si traduce rapidamente nell'impostazione di failbit.

Perché il primo pezzo di codice non funziona sempre correttamente?

Perché non dovresti controllare EOF come condizione del loop. La condizione del ciclo dovrebbe esprimere ciò che stai cercando di fare, che è (ad esempio) l'estrazione di numeri da un flusso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.