函数仅在 C 中不存在时才创建 .dat 文件?



我有这个代码,我需要的函数只创建文件,如果它不存在,如果文件已经存在,它不应该做任何事情。

函数fill_blank_highscore()是创建文件的函数,如果文件不存在,这段代码创建它,但程序关闭,我必须再次运行它

void create_highscore_dat(){
FILE* highscore;
highscore = fopen("highscore.dat", "r");    
if(highscore == NULL) {
fill_blank_highscore();
}
if(highscore == NULL) {
exit(EXIT_FAILURE);
}
fclose(highscore);
}

您不应该在highscore == NULL时报告错误——这是期望的情况。如果打开文件成功,它应该报告一个错误,因为这意味着它已经存在。

void create_highscore_dat(){
FILE* highscore;
highscore = fopen("highscore.dat", "r");    
if(highscore == NULL) { // file doesn't exist, create it
fill_blank_highscore();
} else { // file already exists, abort
fclose(highscore);
printf("highscore.dat already exists, not saving.n");
}
}

如果fopen()无法打开现有文件,您的代码正在调用exit()来终止进程。如果您不希望在必须创建新文件时程序终止,则只需去掉exit()

如果您在"a"模式下使用fopen()打开文件,如果不存在,它将创建一个新文件,否则它将打开现有文件并查找到文件的末尾,保留现有数据完整。因此,例如,如果fopen()成功,然后ftell()/fgetpos()表示文件为空,则在关闭文件之前根据需要使用默认数据填充文件。

int fill_blank_highscore(FILE* highscore)
{
// write to file as needed...
return ...; // 0 on success, < 0 on failure...
}
void create_highscore_dat(){
FILE* highscore = fopen("highscore.dat", "a");
if (highscore != NULL) {
long pos = ftell(highscore);
if (pos == 0) {
if (fill_blank_highscore(highscore) < 0) {
pos = -1L;
}
}
fclose(highscore);
if (pos != -1L) return;
}
exit(EXIT_FAILURE);
}

正如我在评论中所写的,我认为这是一个XY问题。但是,如果您确实希望在文件已经存在时打开失败,则可以使用较低级别的open函数,而不是fopen:

int fd = open("highscore.dat", O_CREAT|O_EXCL|O_RDWR,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
if (fd == -1 && errno == EEXIST)
{
/* File already exist */
}
else if (fd == -1)
{
/* 
File failed to open for other reasons (permissions, IO-error, etc)
*/
perror("Failed to create highscore file");
}
else
{
/* do something with file */
}

O_CREAT允许创建文件,如果文件已经存在,O_EXCL使open失败。O_RDWR使fildescriptorfd可用于读和写。S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP为用户和组设置磁盘上的文件权限为读/写。

标志和模式位应该适应特定的用例,参见man open

文件描述符fd可以转换为FILE *,如果您喜欢使用更高级别的基于流的IO函数。(如你所愿):

else
{
/* do something with file */
FILE *f = fdopen(fd, "r+");
if (!f)
{
close(fd);
perror("Failed to create file stream");
}
else
{
/* Work with `f` */
fill_blank_highscore(f);
fclose(f);  /* `f` owns `fd`, so this will also close `fd` */
}
}

最新更新