Mauricio Martinez
Mauricio Martinez

Reputation: 377

Will fwrite() let you write something past the end of the file size?

FILE *f = fopen("file.txt", "ab+");
fseek(f, NUMBER_BIGGER_THAN_FILE_SIZE, SEEK_SET);
fwrite(&someStruct, sizeof someStruct, 1l, f);

So if I have something like that, will that allow that to be written? And if not, how can I make that happen?

Upvotes: 1

Views: 3050

Answers (2)

Yes, you can fwrite past the end of the file (on most file systems). If you can't, the fwrite is failing (and gives a negative result).

Of course, that requires the prior fseek call to be successful and changing the written file offset. You need to check that. As d3L answered, fseek may only change the offset which won't be used by fwrite for an appended file.

You may want to fopen with some other mode. Don't use a append mode.

For example, you might have the file tryappend.c (it has about 509 bytes) below:

// file tryappend.c, copy it to tryappend.c2 before running
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    const char* filnam = "tryappend.c2";
    FILE *f = fopen(filnam, "a+");
    if (!f) 
       { perror(filnam); exit(EXIT_FAILURE); };
    if (fseek(f, 1024, SEEK_SET)<0) 
       { perror("fseek"); exit(EXIT_FAILURE); };
    const char str[] = "//// ADDED STUFF\n";
    if (fwrite(str, sizeof(str), 1L, f)<0) 
       { perror ("fwrite"); exit(EXIT_FAILURE); }
    fclose(f);
    printf("changed %s\n", filnam);
    return 0;
}

and copy it into tryappend.c2 before running your tryappend executable. Then you can check with a binary editor or with e.g. od on Linux that the fwrite-n stuff has been appended at offset 510 (not 1024), and finally your tryappend.c2 file has only 527 bytes (not something like 1040).

If you insist on direct-accessed files, you could use lower-level system calls such as (on Linux or POSIX) open(2), read(2), write(2), lseek(2), ftruncate(2), mmap(2), close(2), etc... Be aware that for performance reasons you often should use large buffers (so read or write chunks of several kilobytes at least). BTW, on Linux the C standard library (so <stdio.h> routines, including fread, fwrite, fflush, ...) is using such system calls.

You could have files which are not seekable. A good example is on Linux some pseudo files from /proc file system (see proc(5)) such as /proc/self/maps, or popen(3)-ed files.

You could find libraries giving you a slightly higher-level abstraction than direct-accessed files, e.g. sqlite or gdbm (and I recommend using these). Of course, you could use some database. Read also about sparse files.

You should define and document precisely your file format (perhaps using some EBNF notation), byte by byte. You probably should care about the portability of your file format (think of issues like endianness, data alignment, word size), or provide a way to fill or dump your binary file into some more portable textual format.

Upvotes: 1

Marco
Marco

Reputation: 7261

It is possible to write over the end of a file.

However in a mode (append mode) fseek has no effect on fwrite.

This is documented in the C standard, 7.19.5.3 fopen:

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.

Source: https://stackoverflow.com/a/5532426/2005038

Upvotes: 2

Related Questions