I wanted to overwrite an existing file, which should be simple:
#include <stdio.h>
int main()
{
FILE *f;
unsigned char ba;
int i;
f = fopen("junk", "wb");
for (i = 1; i <= 10; i )
fputc(i, f);
fclose(f);
f = fopen("junk", "ab");
fseek(f, 0, SEEK_SET);
for (i = 1; i <= 5; i ) {
printf("Position before: %ld\n", ftell(f));
fputc(99, f);
printf("Position after: %ld\n", ftell(f));
}
fclose(f);
fopen("junk", "rb");
for (i = 1; i <= 10; i ) {
ba = fgetc(f);
printf("%d ", ba);
}
printf("\n");
}
The result is:
Position before: 0
Position after: 11
Position before: 11
Position after: 12
Position before: 12
Position after: 13
Position before: 13
Position after: 14
Position before: 14
Position after: 15
Position before: 15
Position after: 16
Position before: 16
Position after: 17
Position before: 17
Position after: 18
Position before: 18
Position after: 19
Position before: 19
Position after: 20
1 2 3 4 5 6 7 8 9 10
The idea is to write a file in write mode, then reopen in write/append mode, overwrite the first 5 bytes, then open in read mode and read the contents of the 10 bytes out. The result should have been:
99 99 99 99 99 6 7 8 9 10
As you see from the trace, instead <stdio.h>
ignores the fseek()
to zero and appends at the end in any case. Obviously this is distilled from a more complex program, but this behavior makes no sense to me.
CodePudding user response:
You can only write to the end of a file opened for append, regardless of the seeking. That's what it is for. Open in mode "rb " to overwrite. @Weather Vane
Given the requirement "reopen in write/append mode", I see opening with "rb "
[open binary file for update (reading and writing)] still meeting that goal.
Sure, but that behavior is undocumented.
The behavior is well documented in the C spec.
Opening a file with append mode (’a’ as the first character in the mode argument) causes all subsequent writes to the file to be forced to the then current end-of-file, regardless of intervening calls to the fseek function. ... C17dr § 7.21.5.3 6
Other derived documentation may or may not be so informative. When in doubt about the C language or standard library, check the language specification.
CodePudding user response:
The file is open for appending with "ab"
: any output is performed at the end of the file. As you can see from the output, the first fputc()
performs an implied fseek(SEEK_END, 0L, f)
.
If you opened it for "ab "
you could seek anywhere into the file and read from there but all output would still first seek to the end of the file.
If you mean to overwrite a part of the file and leave the rest intact, you should open it with "rb "
.
Also note that the last call to fopen
: fopen("junk", "rb");
does not store the stream pointer to f
. Further reading from f
, that was closed before, works by coincidence, the behavior is actually undefined.