fwrite () не переопределяет текст в Windows (C) - PullRequest
2 голосов
/ 06 июня 2011

Я пишу этот код C, чтобы я мог проверить, может ли fwrite обновить некоторые значения в текстовом файле.Я тестировал на Linux, и он отлично работает.В Windows (Vista 32bit), однако, он просто не работает.Файл остается неизменным после того, как я запишу другой байт, используя: cont = fwrite (& newfield, sizeof (char), 1, fp);

Регистры записываются в файл с использованием разделителя "@" вформат:

Reg1FirstField@Reg1SecondField@Reg2FirstField@Reg2SecondField...

Окончательный файл должен быть: First@1@Second@9@Third@1@

Я также пробовал putc и fprintf, но все безрезультатно.Может кто-нибудь помочь мне с этим?

#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;
}

Ответы [ 5 ]

3 голосов
/ 06 июня 2011

Вам не хватает функции позиционирования файла между чтением и записью. Стандарт гласит:

7.19.5.3 / 6

Когда файл открывается в режиме обновления, ввод и вывод могут выполняться в связанном потоке. Однако ... за вводом не должен следовать непосредственно вывод без промежуточного вызова функции позиционирования файла, если только операция ввода не сталкивается с концом файла. ...

* * 1010
3 голосов
/ 06 июня 2011

Я не знал этого, но здесь они объясняют это: , почему fseek или fflush всегда требуются между чтением и записью в режимах чтения / записи "+"

Вывод: Выдолжен fflush или fseek перед каждой записью при использовании "+".

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

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

Исправление проверено на Cygwin.

0 голосов
/ 06 июня 2011

С этим:

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

Вы открыли файл в режиме «добавления» - это то, что знак плюс делает в этом параметре.В результате все ваши fwrite() вызовы будут относиться к концу файла.

Использование "r+" для режима fopen() не имеет смысла - + ничего не значитв данном случае.

Эта и другие проблемы с fopen() являются причиной того, что я предпочитаю использовать POSIX-определение open().

. Чтобы исправить ваш конкретный случай, избавьтесь от * 1016.* символы из режимов fopen() и учтите, что вам может потребоваться указать двоичный формат в Windows (режимы "wb" и "rb").

0 голосов
/ 06 июня 2011

По крайней мере, здесь, в OSX, ваше значение 9 начинается с добавления в конец файла ... поэтому вы не обновляете фактическое значение регистра для Second в его позиции в файле.По какой-то причине после сканирования соответствующей точки для изменения значений указатель вашего потока фактически находится в конце файла.Например, запуск и компиляция вашего кода в OSX привели к следующему выводу в фактическом текстовом файле:

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

Причина, по которой работает ваше первоначальное чтение, заключается в том, что данные записываются, но они находятся наконец файла.Поэтому, когда вы записываете значение, а затем создаете резервную копию потока и перечитываете значение, это работает, но оно не записывается в предполагаемом месте.

Обновление: Я добавил несколько вызовов к ftell, чтобы увидеть, что происходит с указателем потока, и кажется, что ваши вызовы fscanf работают так, как вы предполагали, но вызов fwrite переходит на конецфайл.Вот модифицированный вывод:

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: Кажется, просто сохранив позицию указателя потока, а затем установив положение указателя потока, вызовчтобы 'fwrite` работал без пропуска до конца файла.Поэтому я добавил:

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

прямо перед звонком на fwrite.Опять же, это на OSX, вы можете увидеть что-то другое в Windows.

0 голосов
/ 06 июня 2011

Вы не проверяете возвращаемые значения на наличие ошибок.Я предполагаю, что файл доступен только для чтения и даже не открывается должным образом.

...