Funciones de la biblioteca C -feof()
Biblioteca estándar de C - <stdio.h>
feof()Se utiliza para detectar si el archivo ya se ha leído hasta el final.
Podemos entenderlo como un «detector de fin»: cada vez que terminamos de leer una parte, le preguntamos: «¿Hemos llegado al final?»
Descripción
Funciones de la biblioteca Cint feof(FILE *stream)Comprueba el indicador de fin de archivo del flujo (stream) dado.
Aquí aparecen dos conceptos nuevos; primero los explicamos por separado:
Flujo (stream)Es una abstracción de entrada/salida en C. Ya sea un archivo en el disco, la entrada del teclado o datos de red, en C todo se trata uniformemente como un «flujo». Puedes imaginarte un flujo como una tubería de agua: los datos fluyen de un extremo al otro.
Indicador de fin de archivo (marca EOF)Es una marca de estado que cada flujo de archivo lleva internamente. Es como un marcador: cuando el contenido del archivo se ha leído por completo, automáticamente pasa a la página de «leído por completo».
La función de feof() es revisar este marcador: si el marcador muestra «leído por completo», feof() devuelve un valor distinto de cero. Si el marcador aún está en «no leído por completo», feof() devuelve 0.
Declaración
A continuación se muestra la declaración de la función feof(), desglosando su significado parte por parte:
int feof(FILE *stream)
intEs el tipo de valor de retorno: feof() devuelve un entero; un valor distinto de cero indica que se llegó al final, y 0 indica que aún no se ha llegado.
FILE *streamEs el parámetro: debes pasar un puntero de archivo (el mismo puntero que devuelve fopen() al abrir el archivo), para indicarle a feof() qué flujo de archivo debe comprobar.
Parámetros
feof() recibe un parámetro:
| Parámetro | Tipo | Descripción |
|---|---|---|
| stream | FILE * | Puntero de archivo, devuelto por la función fopen(), que apunta al archivo abierto que se desea comprobar. |
Valor de retorno
El valor de retorno se describe a continuación:
| Valor de retorno | Significado |
|---|---|
| Valor distinto de cero | El archivo ya se ha leído hasta el final; no hay más contenido que leer. |
| 0 | El archivo aún no se ha leído por completo; se puede continuar leyendo. |
Punto clave: feof() solo devuelve un valor distinto de cero después de que se haya intentado leer más allá del final del archivo. Si acabas de leer el último carácter pero aún no has intentado seguir leyendo, feof() sigue devolviendo 0. Este problema de sincronización se explicará en detalle en la siguiente sección.
Ejemplo
El siguiente ejemplo demuestra el uso correcto de la función feof().
El programa lee el contenido del archivo carácter por carácter; después de leer cada carácter, usa feof() para comprobar si se ha llegado al final.
Ejemplo
int main ()
{
// FILE * es el tipo de puntero de archivo; se utiliza para apuntar a un archivo ya abierto
FILE *fp;
// fgetc() devuelve int en lugar de char, porque puede necesitar devolver EOF (-1)
int c;
// fopen() abre el archivo; "r" indica modo de solo lectura (read)
fp = fopen("file.txt","r");
// Si el archivo no existe o no hay permisos, fopen() devuelve NULL
if(fp == NULL)
{
// perror() imprime el mensaje de error del sistema, lo que ayuda a localizar el problema
perror("Ocurrió un error al abrir el archivo");
return(-1);
}
// Usar un bucle infinito + comprobación interna
// Esto garantiza «primero leer, luego comprobar», evitando leer contenido extra
while(1)
{
// Primer paso: leer un carácter del archivo
c = fgetc(fp);
// Segundo paso: inmediatamente después de leer, usar feof() para comprobar si se llegó al final
if( feof(fp) )
{
// Se llegó al final; salir del bucle y no procesar c
break ;
}
// Tercer paso: solo después de confirmar que no se llegó al final, usar el valor de c
printf("%c", c);
}
// fclose() cierra el archivo y libera los recursos del sistema
fclose(fp);
return(0);
}
Supongamos que tenemos un archivo de textofile.txt, cuyo contenido es el siguiente:
这里是 example.com
Compila y ejecuta el programa anterior; el resultado es:
这里是 example.com
El programa imprime correctamente todo el contenido del archivo, sin caracteres basura adicionales.
Error común: ¿Por qué no se debe poner feof() en la condición del bucle?
Muchos principiantes escriben el siguiente código, que parece más simple, pero en realidad es incorrecto:
Ejemplo incorrecto
int main ()
{
FILE *fp;
int c;
fp = fopen("file.txt","r");
if(fp == NULL)
{
perror("Ocurrió un error al abrir el archivo");
return(-1);
}
// Error: usar feof() como condición de entrada del bucle
while( !feof(fp) )
{
c = fgetc(fp);
printf("%c", c);
}
fclose(fp);
return(0);
}
El resultado de este código incorrecto será:
这里是 example.com
Aparece un carácter basura adicional al final. ¿Por qué sucede esto? A continuación, rastreamos la ejecución del bucle vuelta por vuelta:
| Iteración del bucle | feof() en la entrada del bucle | Lo que lee fgetc() | Lo que imprime printf() | Descripción |
|---|---|---|---|---|
| Iteración 1 | Devuelve 0 (aún no se ha leído) | 'esto' | esto | Normal |
| Iteración 2 | Devuelve 0 (aún no se ha llegado al final) | 'dentro' | dentro | Normal |
| ... | ... | ... | ... | Los caracteres intermedios se imprimen normalmente |
| Última iteración | Devuelve 0 (aún no se ha llegado al final) | 'm' | m | El último carácter normal |
| Iteración extra | Devuelve 0 (¡atención! en este momento acaba de leer 'm', feof aún no sabe que se ha llegado al final) | EOF(-1) | (carácter basura) | ¡Bug! Se leyó una vez de más |
La raíz del problema es que, cuando acabas de leer 'm' (el último carácter del archivo), feof() todavía devuelve 0.
Debe esperar a que «intentes leer una vez más» y descubras que ya no hay más contenido que leer, para recién entonces cambiar la marca interna a «finalizado».
Por lo tanto, la escritura while(!feof(fp)) hace que el bucle se ejecute una iteración de más. En esa iteración extra, fgetc() devuelveEOF(-1), y printf intenta imprimir -1 como un carácter, lo que produce caracteres basura.
Para recordarlo en una frase:feof() es un «informe posterior», no una «advertencia previa». Responde a la pregunta «si al leer la última vez se llegó al final», no «si la próxima lectura llegará al final». Por lo tanto, nunca uses feof() como condición de entrada del bucle.
El patrón correcto es el del ejemplo anterior: primero leer, luego comprobar, y solo usar el contenido leído después de confirmar que es seguro.
Cuándo usar feof()
feof() se usa principalmente en los siguientes dos escenarios:
| Escenario | Uso | Ejemplo |
|---|---|---|
| Lectura de archivos en bucle | Primero leer, luego comprobar (recomendado) | while(1) { c = fgetc(fp); if(feof(fp)) break; ... } |
| Solución de problemas de lectura | Distinguir entre «finalización normal» y «error de lectura» | if(feof(fp)) { /* Finalización normal */ } else if(ferror(fp)) { /* Error de lectura */ } |
En el segundo escenario, fgetc() devuelve EOF por dos posibles razones: realmente se ha terminado de leer (se determina con feof()), o ha ocurrido un error durante la lectura (se determina con ferror()). Ambos casos deben tratarse de forma diferenciada.
Otras extensiones