Domanda

Di recente ho riscontrato un problema causato dall'utilizzo di fstream :: eof (). Ho letto la seguente riga da qui :

  

La funzione eof () restituisce vero se è stata raggiunta la fine del file di input associato, falso altrimenti.

e (erroneamente) presumevo che ciò significasse che se avessi usato fstream :: read () e letto oltre la fine del file, la funzione eof () mi avrebbe detto. Quindi ho fatto una cosa del genere (molto generalizzata):

for(int i = 0; i < max && !file.eof(); i++)
{
     file.read(mything, sizeof(mything));
}

Il problema è venuto a causa di ciò che è spiegato più avanti nella pagina linkata sopra (che inizialmente non sono riuscito a leggere, grazie al primo paragrafo fuorviante):

  

Al contrario, lo stream non passa allo stato EOF se si verifica uno spazio bianco dopo l'ultimo token, ma il tentativo di leggere un altro token non riuscirà comunque. Pertanto, il flag EOF non può essere utilizzato come test in un loop destinato a leggere tutti i contenuti del flusso fino a EOF. Invece, si dovrebbe verificare la condizione di errore dopo un tentativo di leggere.

Quindi ho cambiato, e ora il mio ciclo verifica contro file.fail () anziché file.eof (), e capisco come funziona eof (). La mia domanda è: perché funziona in questo modo? Ci sono situazioni in cui ciò è desiderabile? Mi sembra che una volta superato EOF, hai superato EOF ed eof () dovrebbe tornare vero.

Aggiorna Grazie per le risposte, penso di averlo ottenuto. L'unica operazione che sto eseguendo è read () e controllo immediatamente fail (), quindi penso di stare bene. Ora, la mia domanda è: per quale dovrei usare eof () per?

È stato utile?

Soluzione

Perché in questo modo è in grado di rilevare EOF senza sapere quanto è grande il file. Tutto quello che deve fare è semplicemente provare a leggere e se la lettura è breve (ma non un errore), hai raggiunto la fine del file.

Questo rispecchia la funzionalità della chiamata di sistema read , che file IO in genere finisce per chiamare (roba di win32 può chiamare ReadFile ma credo che la funzionalità sia simile).

Dalla manpage leggi " RETURN VALUE " sezione (enfasi aggiunta):

  

In caso di successo, il numero di byte letti   viene restituito (zero indica la fine di   file) e la posizione del file è   avanzato da questo numero. Non è un   errore se questo numero è inferiore a   il numero di byte richiesti; Questo   può accadere ad esempio perché meno   i byte sono attualmente disponibili al momento   (forse perché eravamo vicini   fine del file o perché stiamo leggendo   da un tubo o da un terminale), oppure   perché read () è stato interrotto da a   segnale. In caso di errore, viene restituito -1 e   errno è impostato in modo appropriato. In questo   caso non viene specificato se   la posizione del file (se presente) cambia.

A proposito: un buon modo per scrivere ciò che volevi sarebbe come questo:

T something;
while(file.read(something, sizeof(something))) {
    // process your 'something'
}

funziona perché file.read (come molti membri di iostream) restituisce un riferimento a iostream stesso. Tutto ciò ha un operatore sovraccarico per consentire il test dello stato del flusso. Analogamente, leggere da std :: cin , mentre (std :: cin > > x) {...} funziona pure.

EDIT: dovresti sapere che test vs. fail possono essere ugualmente sbagliati per lo stesso motivo. Dalla pagina collegata a fail () viene restituito se l'operazione precedente non è riuscita. Il che significa che è necessario eseguire un'operazione di lettura o altra operazione rilevante prima di testarla.

Altri suggerimenti

int n;
std::cin >> n >> std::stripws;

risolve questo problema. a quel punto puoi usare .good () o .eof (). Mi piace usare .good (), poiché se c'è un blocco del disco danneggiato, .good () lo rileverà. ma sono io. .eof () no, dovrai anche aggiungere .fail () || .bad ().

L'ho appena scoperto dopo alcuni studi approfonditi sul problema del consumo di spazi bianchi. Stavo per proporre un ECO a iostream e ifstream, ed ecco, è già stato fatto. :-D

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top