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

7

Quando un principiante inizia a leggere ifstreams, il suo istinto è 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 finché non ha letto l'ultima riga del file due volte. I programmatori C ++ notano che questo non è in realtà come si dovrebbe leggere un file. Invece, di solito raccomandano che chiunque abbia bisogno di leggere un file utilizzi invece un loop come questo:

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

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

    
posta moonman239 10.05.2016 - 18:57
fonte

2 risposte

2

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

Se l'ultima riga del file termina con un carattere di nuova riga ( \n ), la maggior parte delle azioni di lettura smetteranno di leggere quando hanno incontrato quel personaggio e non rileveranno che si tratta dell'ultimo carattere nel file. Nella prossima azione di lettura, è possibile che siano stati aggiunti altri caratteri e che la lettura riesca ad 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 su false se non è stato possibile estrarre un elemento del tipo corretto. Questo succede anche se non ci sono caratteri da leggere.

    
risposta data 11.05.2016 - 11:16
fonte
3

However, C++ programmers note that what always happens is that cin.eof() doesn't return "true" until after the last line has been read twice.

Questo non è ciò che sta accadendo. eofbit non ha alcun ruolo nella conversione in un valore booleano ( stream::operator bool (o operator void* nel vecchio c ++)). Sono coinvolti solo badbit e failbit .

Supponiamo di leggere un file contenente numeri separati da spazi bianchi. Un loop basato su cin.eof() sarà inevitabilmente sbagliato o pieno zeppo di if test. Non stai leggendo fino all'EOF. Stai leggendo i numeri Quindi fai in modo che il tuo codice esprima quella logica:

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

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

Supponiamo d'altra parte che il file termini con 0 42 (nessuna nuova riga alla fine dell'ultima riga). L'ultima buona lettura recupererà il valore 42 che termina sul marcatore EOF. Presumibilmente si desidera elaborarlo 42. Questo è il motivo per cui eofbit non ha alcun ruolo nell'operatore di conversione booleana del flusso di input. Alla prossima chiamata all'operatore di estrazione stream > & gt ;, il macchinario sottostante vede rapidamente che eofbit è già impostato. Ciò comporta rapidamente l'impostazione di failbit .

Why does the first piece of code always fail to work properly?

Perché non dovresti controllare EOF come condizione del ciclo. La condizione del ciclo dovrebbe esprimere quello che stai cercando di fare, che è (per esempio), estrarre numeri da uno stream.

    
risposta data 10.05.2016 - 20:27
fonte

Leggi altre domande sui tag