2009-12-23 11 views
25

¿Es necesario verificar el valor de retorno de fclose? Si hemos abierto con éxito un archivo, ¿cuáles son las posibilidades de que no se cierre?fclose return value check

Gracias!

Saludos, Jay

+0

Gracias a todos por todas las respuestas! :) – Jay

+0

ver también: http://stackoverflow.com/questions/569573/what-is-a-good-programming-pattern-for-handling-return-values-from-stdio-file-wri –

+1

Deberías considerar marcar uno como correcto – caf

Respuesta

32

Cuando fwrite a un archivo, es posible que en realidad no escribir nada, que pueden permanecer en una memoria intermedia (dentro del objeto de archivo). Llamar al fflush realmente lo escribiría en el disco. Esa operación puede fallar, por ejemplo, si acaba de quedarse sin espacio en disco, o si hay algún otro error de E/S.

fclose vacía los almacenamientos intermedios implícitamente también, por lo que puede fallar por las mismas razones.

1

La página del manual fclose indica que puede fallar por alguna de las razones por las cuales close o fflush pueden fallar.

Citando:

La estrecha() llamada al sistema fallará si:

[EBADF]   fildes is not a valid, active file descriptor. 

[EINTR]   Its execution was interrupted by a signal. 

[EIO]    A previously-uncommitted write(2) encountered an 
        input/output error. 

fflush puede fallar por razones que write() podría fallar, básicamente, en el caso de que pueda en realidad escribe/guarda el archivo.

0

Si, en el contexto de su aplicación, puede pensar en algo útil que hacer si falla fclose(), luego pruebe el valor de retorno. Si no puedes, no lo hagas.

+0

OK, pero no dio un ejemplo en el que debe verificarlo. – AraK

+0

No veo que la pregunta era pedir una. –

+0

¿No dice: "¿cuáles son las posibilidades de que no se cierre?" – AraK

2

Debe comprobar siempre resultado de fclose()

1

Una de las razones fclose puede fallar es si hay algún dato todavía amortiguadas y falla la fflush implícita. Lo que recomiendo es llamar siempre a fflush y realizar cualquier gestión de errores allí.

+0

¿En qué consiste el manejo de errores? –

+0

@Neil: el mismo error al manejar la aplicación sería suficiente si una operación de escritura falla (falla la solicitud, registra un error, etc.). –

1

He visto muchas veces que fclose() devuelve un valor distinto de cero.

Y en el examen cuidadoso descubrió que el problema real era con la escritura y no cerrar.

Dado que las cosas que se escriben se almacenan en el búfer antes de que ocurra la escritura real y cuando se llama a un fclose() todo el búfer se vacía. Por lo tanto, cualquier problema al escribir el sufijo amortiguado, digamos como disco lleno, aparece durante fclose(). Como dice David Yell, para escribir una aplicación a prueba de balas, debe considerar el valor de retorno de fclose().

+0

para agregar: la función devuelve cero en caso de éxito, o EOF en la falla –

3

Se puede (y debe) informar del error, pero en un sentido, el stream is still closed:

Después de la llamada a fclose(), cualquier uso de los resultados de transmisión en un comportamiento indefinido.

3
  1. fclose() eliminará cualquier salida no escrita (vía fflush()) antes de regresar, por lo que los resultados de error del write() subyacente no se informó en fwrite() o fprintf() tiempo, pero cuando lo hace el fclose().Como resultado, cualquier error que pueda generar write() o fflush() se puede generar por fclose().

  2. fclose() también llamarán close() que puede generar errores en los clientes NFS, donde el archivo modificado en realidad no se cargan en el servidor remoto hasta close() tiempo. Si el servidor NFS falla, entonces el close() fallará, y por lo tanto fclose() también fallará. Esto podría ser cierto para otros sistemas de archivos en red.

26

De comp.lang.c:

El fclose() llamada puede fallar, y debe ser errores comprueba justo como asiduamente como todas las otras operaciones de archivo. Suena pedante, ¿verdad? Incorrecto. En una vida anterior , el producto de mi empresa logró destruir los datos de un cliente omitiendo una marca de error cuando cerró un archivo. La secuencia fue algo así como (parafraseado):

stream = fopen(tempfile, "w"); 
if (stream == NULL) ... 
    while (more_to_write) 
     if (fwrite(buffer, 1, buflen, stream) != buflen) ... 
fclose (stream); 

/* The new version has been written successfully. Delete 
* the old one and rename. 
*/ 
remove (realfile); 
rename (tempfile, realfile); 

Por supuesto, lo que ocurrió fue que fclose() se quedó sin espacio de disco tratando escribir el último par de bloques de de datos, por lo que el `tempfile' se truncó e inutilizable. Y como no se detectó la falla de fclose() , el programa se adelantó y destruyó la mejor versión existente de los datos en a favor de la versión dañada. Y, como Murphy tendría, a la víctima en este incidente en particular fue la persona encargada del departamento de del cliente, la persona con autoridad a comprar más de nuestro producto o reemplazar con producto de la competencia - y, natch, una persona que ya estaba infeliz con nosotros por otras razones.

que sería un tramo de atribuir todos la miseria que siguió a esta única omisión, pero puede valer la pena señalar que tanto el cliente y mi antigua compañía ya han desaparecido de la ecología corporativa.

¡COMPRUEBE LOS CÓDIGOS DE FALLA!

+0

Haha. Yo también pensé en esa publicación cuando leí la pregunta. Sin embargo, decidí no buscarlo y escribí sobre ello de memoria. –

+0

@Alok: Gran publicación :) .. ocho años pero todavía suena verdadero –

2

Digamos que está generando datos. Tiene datos viejos que fread() de un archivo, y luego procesa los datos, genera más datos y luego los escribe en un archivo nuevo. Tiene cuidado de no sobrescribir el archivo anterior porque sabe que intentar crear un nuevo archivo puede fallar, y le gustaría conservar sus datos antiguos en ese caso (algunos datos son mejores que no tener datos). Después de terminar todos los fwrite() s, que tuvieron éxito (porque revisó meticulosamente el valor de retorno desde fwrite()), fclose() el archivo. Luego, rename() su archivo recién escrito y sobrescribe el archivo anterior.

Si fclose() falló debido a error de escritura (¿disco lleno?), Simplemente sobrescribió su último archivo correcto con algo que podría ser basura. Oops.

Por lo tanto, si es fundamental, debe verificar el valor de retorno de fclose().

En términos de código:

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    FILE *ifp = fopen("in.dat", "rb"); 
    FILE *ofp = fopen("out.dat", "wb"); 
    char buf[BUFSIZ]; 
    size_t n; 
    int success = 1; 

    if (ifp == NULL) { 
     fprintf(stderr, "error opening in.dat\n"); 
     perror("in.dat"); 
     return EXIT_FAILURE; 
    } 

    if (ofp == NULL) { 
     fclose(ifp); 
     fprintf(stderr, "error opening out.dat\n"); 
     perror("out.dat"); 
     return EXIT_FAILURE; 
    } 

    while ((n = fread(buf, 1, sizeof buf, ifp)) > 0) { 
     size_t nw; 
     if ((nw = fwrite(buf, 1, n, ofp)) != n) { 
      fprintf(stderr, "error writing, wrote %lu bytes instead of %lu\n", 
          (unsigned long)n, 
          (unsigned long)nw); 
      fclose(ifp); 
      fclose(ofp); 
      return EXIT_FAILURE; 
     } 
    } 
    if (ferror(ifp)) { 
     fprintf(stderr, "ferror on ifp\n"); 
     fclose(ofp); 
     fclose(ifp); 
     return EXIT_FAILURE; 
    } 

#ifdef MAYLOSE_DATA 
    fclose(ofp); 
    fclose(ifp); 
    rename("out.dat", "in.dat"); /* Oops, may lose data */ 
#else 
    if (fclose(ofp) == EOF) { 
     perror("out.dat"); 
     success = 0; 
    } 
    if (fclose(ifp) == EOF) { 
     perror("in.dat"); 
     success = 0; 
    } 
    if (success) { 
     rename("out.dat", "in.dat"); /* Good */ 
    } 
#endif 
    return EXIT_SUCCESS; 
} 

en el código anterior, hemos sido cuidadosos con fopen(), fwrite() y fread(), pero incluso entonces, no comprobar fclose() puede resultar en la pérdida de datos (cuando se compila con MAYLOSE_DATA definido).

+0

sería genial si le dieras un ejemplo de cómo verificar el valor de retorno para completar –

+0

Hecho. Lo he convertido en una opción de tiempo de compilación para ejecutar el código correcto. –

+0

¡Genial! Excepto que olvidó consultar un par de declaraciones más :) –

0

En cierto sentido, closing a file never fails: se devuelven errores si una operación de escritura pendiente falló, pero se cerrará la secuencia .

Para evitar problemas y garantizar (en la medida de lo que pueda de un programa en C), lo que ha sugerido:

  1. manejar apropiadamente los errores devueltos por fwrite().
  2. Llame al fflush() antes de cerrar la transmisión. Do Recuerde verificar los errores devueltos por fflush().