开发者

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

开发者 https://www.devze.com 2023-03-11 15:27 出处:网络
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 f

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);
fcl开发者_StackOverflow中文版ose(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;
}


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 */


I didn't know it but here they explain it: why fseek or fflush is always required between reading and writing in the read/write "+" modes

Conclusion: You must either fflush or fseek before every write when you use "+".

fseek(fp, 0, SEEK_CUR);
// or
fflush(fp);

cont = fwrite(&newfield, sizeof(char), 1, fp);

Fix verified on Cygwin.


You're not checking any return values for errors. I'm guessing the file is read-only and is not even opening properly.


At least here on OSX, your value 9 is begin appended to the end of the file ... so you're not updating the actual register value for Second at it's position in the file. For some reason after the scan for the appropriate point to modify the values, your stream pointer is actually at the end of the file. For instance, running and compiling your code on OSX produced the following output in the actual text file:

First@1@Second@1@Third@1@9

The reason your initial read-back is working is because the data is being written, but it's at the end of the file. So when you write the value and then back-up the stream and re-read the value, that works, but it's not being written in the location you're assuming.

Update: I've added some calls to ftell to see what's happening to the stream pointer, and it seems that your calls to fscanf are working as you'd assume, but the call to fwrite is jumping to the end of the file. Here's the modified output:

Update field 2 on the second register:
**Stream position: 0
0-1: First
0-2: 1
**Stream position: 8
1-1: Second
**Stream position before write: 15
**Stream position after write: 26
written: 1 bytes, char: 9
1-2: 9
**Stream position after read-back: 26

Update-2: It seems by simply saving the position of the stream-pointer, and then setting the position of the stream-pointer, the call to 'fwrite` worked without skipping to the end of the file. So I added:

fpos_t position;
fgetpos(fp, &position);
fsetpos(fp, &position);

right before the call to fwrite. Again, this is on OSX, you may see something different on Windows.


With this:

fp=fopen("testupdate.txt","w+");
                            ^------ Notice the + sign

You opened the file in "append" mode -- that is what the plus sign does in this parameter. As a result, all of your fwrite() calls will be relative to the end of the file.

Using "r+" for the fopen() mode doesn't make sense -- the + means nothing in this case.

This and other issues with fopen() are why I prefer to use the POSIX-defined open().

To fix your particular case, get rid of the + characters from the fopen() modes, and consider that you might need to specify binary format on Windows ("wb" and "rb" modes).

0

精彩评论

暂无评论...
验证码 换一张
取 消