Home > Blockchain >  How to overwrite using stdio.h?
How to overwrite using stdio.h?

Time:02-05

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.

  • Related