C语言中fopen函数写文件失败,错误码为2。

11

我不理解为什么这似乎失败了,而且 errno 是 2:

char debugText [256];
sprintf (debugText, "C:\\List.txt");
dfile = fopen( debugText, "w");
fprintf ( dfile, "  err %d \n", errno);

我之所以说“似乎”是因为当dfile为空时,文件会被创建并填充我的输出内容。

那么到底发生了什么?


dfile 是什么类型?NULL 的测试在哪里? - David Schwartz
4
请查看strerror()函数,它会返回一个解释errno的字符串。 - Zaffy
对我来说,问题是该文件没有写入权限。在Windows上:右键单击 > 属性 > 安全 > 编辑。然后允许所有用户进行修改。 - Sergio Basurco
@SergioBasurco 或许更好的解决方法是将文件指向允许普通用户写入的位置。并非每个人都拥有管理员权限,这些权限不应用于纠正编程错误。 - hetepeperfan
5个回答

15
所有这些告诉你的只是,在你的fopen调用后,errno的值为2。你不知道调用是否失败,因为你没有检查dfile == NULL。如果输出实际上是写入文件的,那么fopen调用成功了,errno的值可能来自以前的某个调用,很可能是你没有明确进行的调用。
一个成功的fopen调用完全有可能将errno设置为非零值。
失败的调用可以将errno设置为一些非零值,但成功的调用不会将errno设置为0。要检查错误,您需要:
  • 在调用之前将errno设置为0;
  • 进行调用并检查它返回的值,以确定它是成功还是失败;以及
  • 在调用后检查errno的值——但仅当您知道它失败时(否则errno的值毫无意义)。
如果 dfile == NULL,那么 fprintf 调用的行为是未定义的;它可能会失败。
另一方面,你说 dfileNULL。你怎么知道的?你的代码没有检查它。(如果 fopen 调用真的失败了,那么 C:\List.txt 的内容是否可能来自程序之前的运行?)
这个程序输出什么?
#include <stdio.h>
#include <errno.h>
int main(void) {
    char debugText [256];
    FILE *dfile;

    sprintf (debugText, "C:\\List.txt");
    dfile = fopen( debugText, "w");
    if (dfile == NULL) {
        printf("fopen failed, errno = %d\n", errno);
    }
    else {
        printf("fopen succeeded\n");
    }
    return 0;
}

我看到dfile是NULL,因为我在调试模式下逐步执行。那时我开始获取errno。 - JPM
你需要检查程序中的 defile == NULL,如果是,则不要尝试写入文件。为了验证 fopen() 失败的原因,请按照我建议的使用 errno。假设你在 Windows 系统上,打开 "C:\\List.txt" 以进行输出不应该出现 errno==2 的错误,这意味着“没有这样的文件或目录”。(你确实在使用 Windows 吗?而不是在 Cygwin 下?) - Keith Thompson
@JPM:请尝试一下我刚刚在答案中添加的程序。 - Keith Thompson

9
2 ENOENT No such file or directory.  A component of a specified pathname
         did not exist, or the pathname was an empty string.

这里是一份错误代码列表:

http://www.thegeekstuff.com/2010/10/linux-error-codes/

但是,在查看fopen()返回值为NULL之前,您应该先检查一下,因为此时errno中的值可能是从其他地方遗留下来的。


5

没有任何库函数会将errno设置为零。

只有在函数报告错误后才应该检查errno

例如,您的代码应该是:

if ((dfile = fopen(debugText, "w")) == 0)
    ...then fopen() failed and errno is relevant...

如果函数没有报告错误,那么errno中的值可能是任意的。例如,在Solaris上,您经常在成功操作后将errno设置为ENOTTY,因为stdout未连接到终端。这并不意味着实际上发生了任何错误;它只是意味着是否标准输出是终端的测试失败了(因为它不是终端)。


如果文件存在,fopen应该删除并创建一个新文件。很明显路径不为空,也不是不存在的:C:\,所以我不明白为什么dfile是NULL。除非这是VS2010的异常情况? - JPM
你没有证明 dfile == NULL;实际上,由于接下来的 fprintf() 使用了它,所以 dfile 为空的可能性很小(如果它为空,你可能会在 fprintf() 中崩溃)。你需要修改代码以显式测试 dfile,然后我才愿意相信你的断言 dfile 为空(并将错误报告到除 dfile 之外的通道)。 - Jonathan Leffler

3

只需编写文件名: 像下面的示例一样,对我来说效果很好: 它将创建文件并在其中写入用户输入的数字。

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void main() {
    int num;
   FILE *fptr;
   clrscr();
   fptr = fopen("num.txt","w");

   if(fptr == NULL)
   {
     fprintf(stderr,"open error for %s,errno = %d: %s\n",fptr, errno, strerror(errno));
     printf("Error!");
     exit(1);
   }

   printf("Enter num: ");
   scanf("%d",&num);

   fprintf(fptr,"%d",num);
   fclose(fptr);

   getch();

}


1
在我的情况下,我尝试在已挂载的FAT文件系统的闪存驱动器上写入文件时,出现了errno == 2的错误;结果发现,如果文件不符合8.3规则fopen会返回NULL并将errno设置为ENOENT

需要指出的是,我在嵌入式系统中遇到了这种情况,在Windows上不应该出现这个问题。


抱歉,我的错。我编辑了我的回答。 - Andrey Starodubtsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接