Create a file if one doesn't exist - C

239,433

Solution 1

You typically have to do this in a single syscall, or else you will get a race condition.

This will open for reading and writing, creating the file if necessary.

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

If you want to read it and then write a new version from scratch, then do it as two steps.

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

Solution 2

If fptr is NULL, then you don't have an open file. Therefore, you can't freopen it, you should just fopen it.

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

note: Since the behavior of your program varies depending on whether the file is opened in read or write modes, you most probably also need to keep a variable indicating which is the case.

A complete example

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;
}
Share:
239,433

Related videos on Youtube

karoma
Author by

karoma

Updated on July 09, 2022

Comments

  • karoma
    karoma almost 2 years

    I want my program to open a file if it exists, or else create the file. I'm trying the following code but I'm getting a debug assertion at freopen.c. Would I be better off using fclose and then fopen immediately afterward?

    FILE *fptr;
        fptr = fopen("scores.dat", "rb+");
        if(fptr == NULL) //if file does not exist, create it
        {
            freopen("scores.dat", "wb", fptr);
        } 
    
    • gbulmer
      gbulmer about 12 years
      @tbert - I am as worried that people are not upvoting the answer that explains the failure. Thank God it's Friday :-)
  • James McLaughlin
    James McLaughlin about 12 years
    It looks like the OP is trying to open it in read-only mode if it already exists (I don't understand why they want to create it at all in that case, though).
  • Dietrich Epp
    Dietrich Epp about 12 years
    This has a race condition, it will fail if another process creates the file between the two calls to fopen.
  • Dietrich Epp
    Dietrich Epp about 12 years
    Well, if he doesn't want to write to it, he doesn't need to. As far as I know, there's no way to open read-only on the condition that it exists without creating a needless race condition.
  • karoma
    karoma about 12 years
    @JamesMcLaughlin I thought the rb+ will let me write also? After this section of code I need to read everything from the file, then later write the file from scratch.
  • Shahbaz
    Shahbaz about 12 years
    @DietrichEpp Hadn't though of that!
  • gbulmer
    gbulmer about 12 years
    If the initial point "If fptr is NULL, then you don't have an open file. Therefore, you can't reopen it." explains the behaviour the OP is seeing (which I believe it does), then, for clarity, it might be worth editing the text to seperate that point from the subsequent approach to fixing it. (also reopen should be freopen)
  • gbulmer
    gbulmer about 12 years
    @Shahbaz - you're welcome. I think the other answer fails to identify the key point that it will never work. So folks might read that answer and their take away might be about race conditions, especially at it has been upvoted, when it is actually much much simpler. I could imagine spending hours trying to nail the race condition (which isn't there :-)