是否需要检查fclose的返回值?如果我们已成功打开文件,它可能无法关闭的可能性有多大?
谢谢!
此致 杰
答案 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)
fclose()
会在返回之前刷新任何未写入的输出(通过fflush()
),因此write()
不会报告基础fwrite()
的错误结果或fprintf()
时间,但是当您执行fclose()
时。因此,write()
可以生成fflush()
或fclose()
可以生成的任何错误。
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程序中获取),我建议您:
fwrite()
返回的错误。fflush()
。 执行记得检查fflush()
返回的错误。