How to choose open mode with fopen()?

16,694

Solution 1

You will have to deal with the possibly non-existent file in two stages, first assuming that it is there and then dealing with its absence:

if ((f = fopen(filename, "rb+") == 0)
    f = fopen(filename, "wb+");
if (f == 0)
    ...report error...

The "rb+" mode will fail to open a non-existent file (but otherwise behaves as you want). If the file doesn't exist, then "wb+" will do what you want instead (though it could still fail, for example if the file exists but you don't have permission to write to it). You have to hope that you've not been subjected to a TOCTOU (Time of Check, Time of Use) attack with the double attempt.

An alternative approach uses the 3-argument version of the open() system call with appropriate flags to open a file descriptor, and then uses fdopen() to create a file stream from the file descriptor:

#include <fcntl.h>

int fd;
if ((fd = open(filename, O_RDRW | O_CREAT, 0644)) >= 0)
    f = fdopen(fd, "rb+");

You get rather precise control over open() with the flags.

Solution 2

The file modes are clearly documented for fopen (try man 3 fopen on Unix/Linux/OS X).

r+ Open for reading and writing. The stream is positioned at the beginning of the file.

Share:
16,694
Summer_More_More_Tea
Author by

Summer_More_More_Tea

Updated on June 29, 2022

Comments

  • Summer_More_More_Tea
    Summer_More_More_Tea almost 2 years

    I have a problem about file open mode with fopen().

    In my case, I want to seek the cursor freely, may be even beyond EOF sometimes. What's more, I also want to append to it instead of truncating the existing file. I tried to open the file in a+ mode; however, I cannot seek file cursor freely. Each time I seek the cursor beyond EOF, new arrival data will be append to end of the file, not the position I specified. While, if open in w+ mode, the existing file will be truncated. Is there a perfect solution to this problem?


    UPDATE:

    One point not clearly specified is that the file may not always exist; I have to create a new file in that case.

    In fact, I want to process a configuration file. I don't know whether it is good practice to implement like this. Or should I first place an empty configuration file. Thus there is no need to care about the case file does not exist?

    Below is the code snippet:

    FILE *f = fopen(FILE_PATH, "wb+");
    struct record r;
    if (f) {
        if (fread((void *)&r, 1, sizeof(struct record), f) {
            /* File exists, do the normal flow */
        } else {
            if (feof(f)) {
                /* File is newly created, do some initialization */
            }
        }
    } else {
        /* issue a warning */
    }