Home > Enterprise >  Are these two ways of writing at the end of the file equivalent?
Are these two ways of writing at the end of the file equivalent?

Time:12-15

I want to add a 4 at the end of the file and I have thought that I can do this in 2 different ways:

First method:

int a = 4;
FILE *f = fopen("file.txt","wb");
fseek(f,0,SEEK_END);
fwrite(&a,sizeof(int),1,f);

Second method:

int a = 4;
FILE *f = fopen("file.txt","ab");
fwrite(&a,sizeof(int),1,f);

I think they are exactly the same. Am I right?

CodePudding user response:

These are not the same.

The "wb" mode will truncate the file to zero size, while the "ab" mode will open the file and simply place the file pointer at the end.

So if you don't want to wipe out the contents of your file, use "ab".

CodePudding user response:

int a = 4;
FILE *f = fopen("file.txt","wb");
fseek(f,0,SEEK_END);
fwrite(&a,sizeof(int),1,f);

This doesn't work as you expect, because opening in "wb" truncates the existing file (empties it). If you changed the mode to "r b" and seeked to the end, it would work similarly, assuming that SEEK_END is supported (the standard does not require it, but most implementations support it), but it would require that the file already exists (only w and a based modes will create a file when it does not exist).

Your second option is safer, because:

  1. It works even if the file doesn't already exist
  2. It doesn't rely on SEEK_END support
  3. It's (partially) multi-thread/multi-process safe (subject to varied implementation details)

That said, it's still not guaranteed; the C standard allows for some weird systems, where binary files might be larger than the data written due to the system imposing null padding at the end (e.g. files might be required to be a multiple of 512 bytes in size, so if you write 400 bytes, the file would end with 112 '\0's). I suspect these are the same sorts of systems that might not support SEEK_END. If you're on one of those systems, the appended data would be appended after the padding. That said, if you're on one of those systems, you've got other issues (you can't actually know where the "real" data ends without writing length metadata to the file itself; at that point, you're stuck prefixing all your files with a length and using a SEEK_SET based seek for when you want to append, and it gets nuts).

CodePudding user response:

In addition to other answer, unless I miss something (related to binary file), "w" flat makes fopen truncate the file to 0 if it exists.

From man page:

   w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.

Checked on my computer: you can run the code 10 times, you still have a file.txt of length 4, containing int 4 (that is, on my LE machine, bytes 4, 0, 0, 0).

So, if I summarize both answers: your 1st solution doesn't work, because fseek(f, 0, SEEK_END) is useless, since file is size 0, and therefore, writing already occurs at end (which is the same as beginning of file)

Second solution may not work, because you'd have no guarantee that file is positioned at it ends [edit: I see that this is disputed in comments tho]. So, I'd say, no, they are not equivalent. On my PC, calling ten times the 1st code creates a 4 bytes file. Calling ten times the second creates a 40 bytes file. Regardless of whether that 2nd behavior is UB or not, either way, it is different than the 1st behavior.

  • Related