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


11

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 usé este código, noté que no se detenía hasta que había leído la última línea del archivo dos veces. Los programadores de C ++ notan que no es así como uno debería leer un archivo. En cambio, generalmente recomiendan que quien necesite leer un archivo use un bucle como este en su lugar:

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

¿Por qué el primer fragmento de código siempre no funciona correctamente?


Pensé que habría un duplicado, pero no puedo encontrar uno aquí. Hay muchos duplicados en stackoverflow.
David Hammen

Respuestas:


4

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

Si la última línea del archivo termina con un carácter de nueva línea ( \n), la mayoría de las acciones de lectura dejarán de leer cuando se encuentren con ese carácter y no detecten que es el último carácter del archivo. En la siguiente acción de lectura, incluso puede ser 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 se evaluó como falso si no podía extraer un elemento del tipo correcto. Esto también sucede si no quedan caracteres para leer.


4

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

Eso no es lo que está pasando. El eofbitno juega ningún papel en la conversión a un booleano ( stream::operator bool(o operator void*en c ++ anterior)). Solo los badbity failbitestán involucrados.

Suponga que está leyendo un archivo que contiene números separados por espacios en blanco. Un bucle basado cin.eof()inevitablemente será incorrecto o estará lleno de ifpruebas. No estás leyendo hasta EOF. Estás leyendo números. Entonces, haga que su 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\no solo 0 42(no hay una nueva línea al final de la última línea en el archivo). Si el archivo termina con 0 42\n, la última lectura correcta recuperará el valor 42 y leerá ese marcador final de final de línea. Tenga en cuenta que el marcador EOF aún no se ha leído. La función process_valuese llama con 42. La siguiente llamada al operador de extracción de flujo >> lee el EOF, y dado que no se ha extraído nada, se establecerán ambos eofbity failbit.

Supongamos, por otro lado, que el archivo termina con 0 42(sin nueva línea al final de la última línea). La última lectura correcta recuperará el valor 42 que termina en el marcador EOF. Presumiblemente desea procesar ese 42. Es por eso eofbitque no juega un papel en el operador de conversión booleana de flujo de entrada. En la próxima llamada al operador de extracción de flujo >>, la maquinaria subyacente rápidamente ve que eofbitya está configurado. Esto resulta rápidamente en la configuración de failbit.

¿Por qué el primer fragmento de código siempre no funciona correctamente?

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.