fclose返回值检查

时间:2009-12-23 17:42:48

标签: c file-io

是否需要检查fclose的返回值?如果我们已成功打开文件,它可能无法关闭的可能性有多大?

谢谢!

此致 杰

11 个答案:

答案 0 :(得分:35)

当你fwrite到文件时,它可能实际上没有写任何东西,它可能会留在缓冲区中(在FILE对象内)。调用fflush实际上会将其写入磁盘。 该操作可能会失败,例如,如果您的磁盘空间不足,或者存在其他一些I / O错误。

fclose也会隐式刷新缓冲区,因此可能会因同样的原因而失败。

答案 1 :(得分:29)

来自comp.lang.c

  

fclose()调用可能会失败,应该   像勤奋地进行错误检查   作为所有其他文件操作。   听起来很迂腐吧?错误。在一个   以前的生活,我公司的产品   设法摧毁了客户的数据   通过省略检查失败的时候   关闭文件。序列去了   像(释义)那样的东西:

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); 
     

当然,发生了什么事   fclose()尝试用尽磁盘空间   写最后几块   数据,所以`tempfile'被截断了   并且无法使用。而且因为fclose()   程序无法检测到故障   走到前面,摧毁了   最好的现有数据版本   赞成受损版本。并作为   墨菲会有它,受害者   这个特殊的事件是   客户负责人   部门,有权威的人   购买更多我们的产品或更换   它与竞争对手的产品 -   而且,natch,一个已经是的人   因其他原因对我们不满意。

     

归咎于所有人   随之而来的苦难就是这个单身   遗漏,但值得指出   顾客和我的   以前的公司已经消失了   来自企业生态。

     

检查这些失败的代码!

答案 2 :(得分:5)

您可以(并且应该)报告错误,但从某种意义上说,stream is still closed

  

在调用fclose()之后,对流的任何使用都会导致未定义的行为。

答案 3 :(得分:3)

  1. fclose()会在返回之前刷新任何未写入的输出(通过fflush()),因此write()不会报告基础fwrite()的错误结果或fprintf()时间,但是当您执行fclose()时。因此,write()可以生成fflush()fclose()可以生成的任何错误。

  2. fclose()还会调用close(),这会在NFS客户端上生成错误,其中更改的文件在close()时间之前未实际上传到远程服务器。如果NFS服务器崩溃,则close()将失败,因此fclose()也将失败。对于其他网络文件系统可能也是如此。

答案 4 :(得分:2)

您必须始终检查fclose()

的结果

答案 5 :(得分:2)

假设您正在生成数据。您拥有来自文件的fread()旧数据,然后对数据进行一些处理,生成更多数据,然后将其写入新文件。您要小心不要覆盖旧文件,因为您知道尝试创建新文件可能会失败,并且您希望在这种情况下保留旧数据(某些数据优于无数据)。完成所有fwrite()后,这些都成功(因为您仔细检查了fwrite()的返回值),您fclose()该文件。然后,您rename()刚刚写好的文件并覆盖旧文件。

如果fclose()由于写入错误(磁盘已满?)而失败,那么您只是用可能是垃圾的东西覆盖了您的上一个好文件。糟糕。

因此,如果它很重要,您应该检查fclose()的返回值。

就代码而言:

#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;
}

在上面的代码中,我们对fopen()fwrite()fread()一直保持谨慎,但即便如此,不检查fclose()可能会导致数据丢失(当编译时已定义MAYLOSE_DATA

答案 6 :(得分:1)

fclose手册页引用它可能因为任何关闭或fflush失败的原因而失败。

引用:

  

如果出现以下情况,则close()系统调用将失败:

 [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可能因write()失败的原因而失败,基本上是因为您无法实际写入/保存文件。

答案 7 :(得分:1)

fclose失败的一个原因是,如果仍有任何数据仍然被缓冲并且隐式fflush失败。我建议总是调用fflush并在那里进行任何错误处理。

答案 8 :(得分:1)

我已经多次看到fclose()返回非零值。

经过仔细检查发现实际问题是写的而不是fclose。

由于正在写入的内容在实际写入发生之前被缓冲,并且当调用fclose()时,所有缓冲区都被刷新。因此,在fclose()期间出现写缓冲后缀的任何问题,比如磁盘已满。正如David Yell所说,要编写防弹应用程序,您需要考虑fclose()的返回值。

答案 9 :(得分:0)

如果在应用程序的上下文中,如果fclose()失败,您可以考虑做一些有用的事情,然后测试返回值。如果你不能,不要。

答案 10 :(得分:0)

从某种意义上说,closing a file never fails:如果挂起的写入操作失败,则会返回错误,但关闭。

为避免出现问题并确保(尽可能从C程序中获取),我建议您:

  1. 正确处理fwrite()返回的错误。
  2. 关闭流之前调用fflush()执行记得检查fflush()返回的错误。