如果文件不存在,则创建一个文件 - C

48

我希望我的程序能够打开一个已经存在的文件,如果不存在则创建该文件。我正在尝试以下代码,但是在 freopen.c 中出现了调试断言(debug assertion)。我是否最好使用 fclose 然后立即使用 fopen?

FILE *fptr;
    fptr = fopen("scores.dat", "rb+");
    if(fptr == NULL) //if file does not exist, create it
    {
        freopen("scores.dat", "wb", fptr);
    } 

@tbert - 我很担心人们没有给解释失败的答案点赞。感谢上帝,今天是星期五 :-) - gbulmer
2个回答

67

通常你需要在一个系统调用中完成这个操作,否则会出现竞争条件。

这将以读写方式打开文件,并在必要时创建文件。

FILE *fp = fopen("scores.dat", "ab+");

如果你想阅读它,然后从头开始写一个新版本,那么请分两步进行。

FILE *fp = fopen("scores.dat", "rb");
if (fp) {
    read_scores(fp);
}

// Later...

// truncates the file
FILE *fp = fopen("scores.dat", "wb");
if (!fp)
    error();
write_scores(fp);

看起来,如果已经存在,则OP正在尝试以只读模式打开它(虽然我不理解他们为什么要在那种情况下创建它)。 - James M
如果他不想写入它,也不需要这样做。据我所知,在不创建不必要的竞争条件的情况下,没有办法在只读条件下打开它。 - Dietrich Epp
@JamesMcLaughlin 我以为 rb+ 可以让我进行写入操作?在这段代码之后,我需要从文件中读取所有内容,然后稍后再从头开始写入文件。 - karoma

11

如果fptrNULL,那么你没有打开的文件。因此,您不能使用freopen,应该使用fopen

FILE *fptr;
fptr = fopen("scores.dat", "rb+");
if(fptr == NULL) //if file does not exist, create it
{
    fptr = fopen("scores.dat", "wb");
}

注意:由于您的程序的行为取决于文件是以读模式还是写模式打开,因此您很可能需要保持一个变量来指示文件的情况。

完整示例

int main()
{
    FILE *fptr;
    char there_was_error = 0;
    char opened_in_read  = 1;
    fptr = fopen("scores.dat", "rb+");
    if(fptr == NULL) //if file does not exist, create it
    {
        opened_in_read = 0;
        fptr = fopen("scores.dat", "wb");
        if (fptr == NULL)
            there_was_error = 1;
    }
    if (there_was_error)
    {
        printf("Disc full or no permission\n");
        return EXIT_FAILURE;
    }
    if (opened_in_read)
        printf("The file is opened in read mode."
               " Let's read some cached data\n");
    else
        printf("The file is opened in write mode."
               " Let's do some processing and cache the results\n");
    return EXIT_SUCCESS;
}

3
这段代码存在竞态条件,如果在两次调用 fopen 之间有其他进程创建了该文件,那么它将失败。 - Dietrich Epp
@DietrichEpp 想不到! - Shahbaz
2
如果初始点“如果fptrNULL,那么您没有打开的文件。因此,您无法重新打开它。”解释了OP所看到的行为(我相信它确实这样做),那么为了清晰起见,将文本编辑以将该点与随后的修复方法分开可能是值得的。(同时,reopen应更正为freopen) - gbulmer
2
@Shahbaz - 不用谢。我认为其他答案没有明确指出一个关键点,那就是它永远不会奏效。因此,人们可能会读到这个答案,并且他们的理解可能会涉及到竞态条件,尤其是在被点赞后,但实际上要简单得多。我可以想象花费数小时来试图找出竞态条件(当事实上并不存在 :-) - gbulmer

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