write read fscanf files delete create c file-io

c - read - Verifique el valor de retorno



using files c (11)

¿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?

¡Gracias!

Saludos, Jay


  1. fclose() cualquier resultado no escrito (a través de fflush() ) antes de volver, por lo que los resultados de error de la write() subyacente write() no se informarán en fwrite() o fprintf() , pero cuando lo haga, fclose() . Como resultado, cualquier error que write() o fflush() puedan generar puede ser generado por fclose() .

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


De comp.lang.c :

La llamada a fclose () puede fallar, y debe verificarse con un error tan 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 al omitir una verificación de falla al cerrar 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 sucedió fue que fclose () se quedó sin espacio en el disco tratando de escribir los últimos dos bloques de datos, por lo que el `tempfile ''se truncó e inutilizable. Y como no se detectó la falla de fclose (), el programa siguió adelante y destruyó la mejor versión existente de los datos a favor de la versión dañada. Y, como Murphy lo tendría, la víctima en este incidente en particular era la persona a cargo del departamento del cliente, la persona con autoridad para comprar más de nuestro producto o reemplazarlo por un producto de la competencia, y, naturalmente, una persona que ya no estaba contento con nosotros por otras razones.

Sería exagerado atribuir toda la miseria resultante a esta única omisión, pero puede valer la pena señalar que tanto el cliente como mi empresa anterior se han desvanecido de la ecología corporativa.

¡COMPRUEBE LOS CÓDIGOS DE FALLA!


Debes SIEMPRE verificar el resultado de fclose ()


Digamos que estás generando datos. Usted tiene datos viejos que fread() desde 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 tienen éxito (porque revisó meticulosamente el valor de retorno de fwrite() ), fclose() el archivo fclose() . Luego, rename() su archivo recién escrito y sobrescribe el archivo anterior.

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

Entonces, si es crítico, 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 tenido cuidado con fopen() , fwrite() y fread() , pero aun así, si no se verifica fclose() puede perder la información (cuando se compila con MAYLOSE_DATA definido).


En cierto sentido, el cierre de un archivo nunca falla : se devuelven errores si falla una operación de escritura pendiente, pero la transmisión se cerrará.

Para evitar problemas y garantizar (en la medida de lo posible desde un programa C), le sugiero que:

  1. Manejar adecuadamente los errores devueltos por fwrite() .
  2. Llame a fflush() antes de cerrar la transmisión. Recuerde verificar los errores devueltos por fflush() .

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

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

Como 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 ().


La página man de fclose que puede fallar por alguna de las razones por las cuales close or fflush puede fallar.

Citando:

La llamada al sistema close () 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 () fallaría, básicamente en el caso de que no pueda escribir / guardar el archivo.


Podría (y debería) informar el error, pero en cierto sentido, la transmisión aún está cerrada :

Después de la llamada a fclose (), cualquier uso de la secuencia da como resultado un comportamiento indefinido.


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


Uno de los motivos por los que fclose puede fallar es si todavía hay datos almacenados en el búfer y el fflush implícito falla. Lo que recomiendo es llamar siempre a fflush y realizar cualquier gestión de errores allí.


Cuando escribe en un archivo, es posible que no escriba nada, puede permanecer en un búfer (dentro del objeto ARCHIVO). Llamar a 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 los buffers también implícitamente, por lo que puede fallar por las mismas razones.