-1

I want to add a structure to a binary file but first i need to check whether the file has previous data stored in it, and if not i can add the structure,otherwise ill have to read all the stored data and stick the structure in its correct place, but i got confused about how to check if the file is empty ,i thought about trying something like this:

size = 0
if(fp!=NULL)
{
    fseek (fp, 0, SEEK_END);
    size = ftell (fp);
    rewind(fp);
}
if (size==0)
{
  // print your error message here
 }

but if the file is empty or still not created how can the file pointer not be NULL ? whats the point of using ftell() if i can simply do something like this :

if(fp==NULL){fp=fopen("data.bin","wb");

   fwrite(&struct,sizeof(struct),1,ptf);
   fclose(fp);}

i know that NULL can be returned in other cases such as protected files but still i cant understand how using ftell() is effective when file pointers will always return NULL if the file is empty.any help will be appreciated :)

Ammar Brk
  • 1
  • 2
  • 3
    The file pointer will not be NULL just because the file is empty. Why do you think it is? – William Pursell May 12 '18 at 05:04
  • Please add the line to your first example that initializes `fp` . You do not seem to understand when it is a NULL and when it is not. And the best way to check if a file is empty or not is to obtain its size with `fstat`. – DYZ May 12 '18 at 05:05
  • i tried reading from an empty bin file and it was supposed to give me an error message if the fp is NULL , and it did gave me an error – Ammar Brk May 12 '18 at 05:06
  • @Dyz fp=fopen("data.bin","rb"); – Ammar Brk May 12 '18 at 05:11
  • 2
    You mean `fp`, not `ptf`, right? Function `fopen` returns NULL only when the file cannot be opened, not when it is empty. – DYZ May 12 '18 at 05:12
  • sorry i edited it ^^"" @DyZ – Ammar Brk May 12 '18 at 05:14
  • @DyZ oooh !! so if a file is existed but empty it would not give NULL ? but if it wasn't existed it would right ? – Ammar Brk May 12 '18 at 05:17
  • 2
    Correct. You should have read the description of the function before using it. – DYZ May 12 '18 at 05:19
  • thank you very much and yeah youre right ^^" i learned it from a programming class and didnt think about reading the description – Ammar Brk May 12 '18 at 05:22
  • 1
    No, NOT entirely correct. Calling `fopen()` with a path designating a non-existant file will attempt to *create* the file, too. That attempt can fail for various reasons, as can attempts to open files that do exist. `fopen()` returns `NULL` in those cases, and non-NULL when it successfully opens the file, whether it existed before the `fopen()` call or not. – John Bollinger May 12 '18 at 05:46
  • 1
    ... though `"rb"` mode never attempts to create the file if it didn't exist in the first place. – Antti Haapala -- Слава Україні May 12 '18 at 05:55
  • 1
    Since you are going to read from the file if it is not empty, you can as well begin by trying to read from it. If that fails, it's empty. – Arndt Jonasson May 12 '18 at 06:11
  • @AmmarBrk: on what operating system? Do you care about several processes running your program at the same time? What is your application doing? Is it some kind of server? Please **edit your question** to improve it – Basile Starynkevitch May 12 '18 at 08:42
  • @AmmarBrk You can mark this question as resolved by clicking the check mark next to the answer you found most useful. – Increasingly Idiotic May 17 '18 at 20:22

2 Answers2

2

i need to check whether the file has previous data stored in it

There might be no portable and robust way to do that (that file might change during the check, because other processes are using it). For example, on Unix or Linux, that file might be opened by another process writing into it while your own program is running (and that might even happen between your ftell and your rewind). And your program might be running in several processes.

You could use operating system specific functions. For POSIX (including Linux and many Unixes like MacOSX or Android), you might use stat(2) to query the file status (including its size with st_size). But after that, some other process might still write data into that file.

You might consider advisory locking, e.g. with flock(2), but then you adopt the system-wide convention that every program using that file would lock it.

You could use some database with ACID properties. Look into sqlite or into RDBMS systems like PostGreSQL or MariaDB. Or indexed file library like gdbm.

You can continue coding with the implicit assumption (but be aware of it) that only your program is using that file, and that your program has at most one process running it.

if the file is empty [...] how can the file pointer not be NULL ?

As Increasingly Idiotic answered, fopen can fail, but usually don't fail on empty files. Of course, you need to handle fopen failure (see also this). So most of the time, your fp would be valid, and your code chunk (assuming no other process is changing that file simulateously) using ftell and rewind is an approximate way to check that the file is empty. BTW, if you read (e.g. with fread or fgetc) something from that file, that read would fail if your file was empty, so you probably don't need to check its emptiness before.

A POSIX specific way to query the status (including size) of some fopen-ed file is to use fileno(3) and fstat(2) together like fstat(fileno(fp), &mystat) after having declared struct stat mystat;

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

fopen() does not return NULL for empty files. From the documentation:

If successful, returns a pointer to the object that controls the opened file stream ... On error, returns a null pointer.

NULL is returned only when the file could not be opened. The file could fail to open due to any number of reasons such as:

In your case, if fp == NULL you'll need to figure out why fopen failed and handle each case accordingly. In most cases, an empty file will open just fine and return a non NULL file pointer.

Increasingly Idiotic
  • 5,700
  • 5
  • 35
  • 73