Funciones de la biblioteca C -feof()

C 标准库 - <stdio.h>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ámetroTipoDescripción
streamFILE *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 retornoSignificado
Valor distinto de ceroEl archivo ya se ha leído hasta el final; no hay más contenido que leer.
0El 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

#include <stdio.h>

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

#include <stdio.h>

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 buclefeof() en la entrada del bucleLo que lee fgetc()Lo que imprime printf()Descripción
Iteración 1Devuelve 0 (aún no se ha leído)'esto'estoNormal
Iteración 2Devuelve 0 (aún no se ha llegado al final)'dentro'dentroNormal
............Los caracteres intermedios se imprimen normalmente
Última iteraciónDevuelve 0 (aún no se ha llegado al final)'m'mEl último carácter normal
Iteración extraDevuelve 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:

EscenarioUsoEjemplo
Lectura de archivos en buclePrimero leer, luego comprobar (recomendado)while(1) { c = fgetc(fp); if(feof(fp)) break; ... }
Solución de problemas de lecturaDistinguir 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.

C 标准库 - <stdio.h>Biblioteca estándar de C - <stdio.h>

Otras extensiones