Search code examples
cfile-iofwrite

fwrite() does not override text in Windows (C)


I write this C code so that I could test whether fwrite could update some values in a text file. I tested on Linux and it works fine. In Windows (vista 32bits), however, it simply does not work. The file remains unchanged after I write a different byte using: cont = fwrite(&newfield, sizeof(char), 1, fp);

The registers are written on the file using a "@" separator, in the format:

Reg1FirstField@Reg1SecondField@Reg2FirstField@Reg2SecondField...

The final file should be: First@1@Second@9@Third@1@

I also tried putc and fprintf, all with no result. Can someone please help me with this?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct test {
char field1[20];
char field2;
} TEST;

int main(void) {
    FILE *fp;
    TEST reg, regread;
    char regwrite[22];
    int i, cont, charwritten;

    fp=fopen("testupdate.txt","w+");

    strcpy(reg.field1,"First");
    reg.field2 = '1';
    sprintf(regwrite,"%s@%c@", reg.field1, reg.field2);
    cont = (int)strlen(regwrite);
    charwritten = fwrite(regwrite,cont,1,fp);
    fflush(fp);

    strcpy(reg.field1,"Second");
    reg.field2 = '1';
    sprintf(regwrite,"%s@%c@", reg.field1, reg.field2);
    cont = (int)strlen(regwrite);
    charwritten = fwrite(regwrite,cont,1,fp);
    fflush(fp);

    strcpy(reg.field1,"Third");
    reg.field2 = '1';
    sprintf(regwrite,"%s@%c@", reg.field1, reg.field2);
    cont = (int)strlen(regwrite);
    charwritten = fwrite(regwrite,cont,1,fp);
    fflush(fp);
    fclose(fp);

    // open file to update
    fp=fopen("testupdate.txt","r+");

    printf("\nUpdate field 2 on the second register:\n");
    char aux[22];
    // search for second register and update field 2
    for (i = 0; i < 3; i ++) {
       fscanf(fp,"%22[^@]@", aux);
       printf("%d-1: %s\n", i, aux);
       if (strcmp(aux, "Second") == 0) {
            char newfield = '9';
            cont = fwrite(&newfield, sizeof(char), 1, fp);
            printf("written: %d bytes, char: %c\n", cont, newfield);
            // goes back one byte in order to read properly 
            // on the next fscanf
            fseek(fp,-1,SEEK_CUR);
        } 
        fscanf(fp,"%22[^@]@", aux);
        printf("%d-2: %s\n",i, aux);
        aux[0] = '\0';
}
fflush(fp);
fclose(fp);

// open file to see if the update was made
fp=fopen("testupdate.txt","r");
for (i = 0; i < 3; i ++) {
   fscanf(fp,"%22[^@]@", aux);
   printf("%d-1: %s\n", i, aux);
   fscanf(fp,"%22[^@]@",aux);
   printf("%d-2: %s\n",i, aux);
   aux[0] = '\0';
}
fclose(fp);
getchar();

return 0;
}

Solution

  • You're missing a file positioning function between the read and write. The Standard says:

    7.19.5.3/6

    When a file is opened with update mode, both input and output may be performed on the associated stream. However, ... input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. ...

    for (i = 0; i < 3; i ++) {
       fscanf(fp,"%22[^@]@", aux);                              /* read */
       printf("%d-1: %s\n", i, aux);
       if (strcmp(aux, "Second") == 0) {
            char newfield = '9';
    
            /* added a file positioning function */
            fseek(fp, 0, SEEK_CUR);                             /* don't move */
    
            cont = fwrite(&newfield, sizeof(char), 1, fp);      /* write */