¿Por qué ifstream.eof () no devuelve TRUE después de leer la última línea de un archivo?

7

Cuando un principiante comienza a leer ifstreams, su instinto es leer el archivo usando un bucle que generalmente se ve así:

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

Sin embargo, cuando utilicé este código noté que no se detuvo hasta que leyó la última línea del archivo dos veces. Los programadores de C ++ notan que esto no es realmente cómo se debe leer un archivo. En su lugar, generalmente recomiendan que quien necesite leer un archivo use un bucle como este:

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

¿Por qué la primera parte del código no siempre funciona correctamente?

    
pregunta moonman239 10.05.2016 - 18:57

2 respuestas

2

El bucle while (!ifstream.eof()) no funciona, porque las secuencias / archivos en C y C ++ no predicen cuándo ha llegado al final del archivo, sino que indica si ha intentado leer más allá de el final del archivo.

Si la última línea del archivo termina con un carácter de nueva línea ( \n ), entonces la acción más leída dejará de leer cuando se hayan encontrado con ese carácter y no detecten que sea el último carácter en el archivo. expediente. En la siguiente acción de lectura, puede ser incluso que se hayan agregado más caracteres y que la lectura logre extraerlos.

El bucle que usa el operador de extracción de flujo ( while (ifstream >> someVar) ) funciona porque el resultado del operador de extracción de flujo evaluó como falso si no pudo extraer un elemento del tipo correcto. Esto también sucede si no hay caracteres para leer.

    
respondido por el Bart van Ingen Schenau 11.05.2016 - 11:16
3
  

Sin embargo, los programadores de C ++ notan que lo que siempre sucede es que cin.eof () no devuelve "true" hasta que la última línea se haya leído dos veces.

Eso no es lo que está sucediendo. El eofbit no desempeña ningún papel en la conversión a un valor booleano ( stream::operator bool (o operator void* en c ++ anterior)). Solo están involucrados badbit y failbit .

Supongamos que está leyendo un archivo que contiene números separados por espacios en blanco. Un bucle basado en cin.eof() inevitablemente será incorrecto o estará repleto de pruebas de if . No estás leyendo hasta EOF. Estás leyendo números. Así que haz que tu código exprese esa lógica:

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

Esto funcionará si la última línea del archivo termina con 0 42\n o simplemente 0 42 (no hay una línea nueva al final de la última línea del archivo). Si el archivo termina con 0 42\n , la última lectura correcta recuperará el valor 42 y leerá el marcador de final de línea final. Tenga en cuenta que el marcador EOF todavía no se ha leído. La función process_value se llama con 42 . La siguiente llamada al operador de extracción de flujo > > lee el EOF y, como no se ha extraído nada, se establecerán eofbit y failbit .

Supongamos, por otro lado, que el archivo termina con 0 42 (no hay nueva línea al final de la última línea). La última lectura correcta recuperará el valor 42 que termina en el marcador EOF. Es de suponer que desea procesar ese 42. Esta es la razón por la que eofbit no desempeña un papel en el operador de conversión booleana de la secuencia de entrada. En la próxima llamada al operador de extracción de flujo > & gt ;, la maquinaria subyacente ve rápidamente que el eofbit ya está configurado. Esto se traduce rápidamente en la configuración de failbit .

  

¿Por qué la primera parte del código no siempre funciona correctamente?

Porque no deberías estar comprobando EOF como condición de bucle. La condición de bucle debe expresar lo que está intentando hacer, que es (por ejemplo) extraer números de una secuencia.

    
respondido por el David Hammen 10.05.2016 - 20:27

Lea otras preguntas en las etiquetas