首页 > 解决方案 > 无法在文件开始时重写数据,但我可以在 C 中以追加模式在末尾应用

问题描述

我想将学生信息存储在 C 中的文件中,我选择以二进制文件格式写入。首先我以写入模式将所有学生数据写入文件。前 4 个字节(int)代表学生人数,后面的数据用于存储学生信息。

当我想将更多学生数据附加到文件时,我可以在文件末尾以附加模式应用学生数据,但无法更新文件开头的学生数(前 4 个字节(int)),它们是已经以写入模式写入。手册页中没有说明我无法重写已经以写入模式写入的数据。下面是代码。提前致谢。

typedef struct
{
    char* rollNo;
    char* name;
    char* grade;
}Student;

int numStudents;

void append(Student* newStudent){
    
    FILE *fp;
    if((fp=fopen("students.bin","ab"))==NULL){ f_err_report(ERR_OPEN);exit(1);}
    
    //appending the new student at the end of the file
    
    // writing rollNo

    int len;
    len = strlen(newStudent->rollNo)+1;

    if(fwrite(&len,sizeof(int),1,fp)!=1) {
        f_err_report(ERR_WRITE);

    }
    if(fwrite(newStudent->rollNo,sizeof(char)*len,1,fp)!=1) {
        f_err_report(ERR_WRITE);

    }


    //writing name

    len = strlen(newStudent->name)+1;

    if(fwrite(&len,sizeof(int),1,fp)!=1) {
        f_err_report(ERR_WRITE);

    }
    if(fwrite(newStudent->name,sizeof(char)*len,1,fp)!=1) {
        f_err_report(ERR_WRITE);

    }

    //writing grade

    len = strlen(newStudent]->grade)+1;

    if(fwrite(&len,sizeof(int),1,fp)!=1) {
        f_err_report(ERR_WRITE);

    }
    if(fwrite(newStudent->grade,sizeof(char)*len,1,fp)!=1) {
        f_err_report(ERR_WRITE);

    }


    //updating the total number of students at the file starting. But this doesn't happen!!! It stays same as when I wrote in "write mode" previously

  numStudents++;

    rewind(fp);

    if(fwrite(&numStudents,sizeof(int),1,fp)!=1){
        f_err_report(ERR_WRITE);
    }
    printf("appended to the list \n");


    fclose(fp);
}

标签: cfile-handling

解决方案


当你打电话

rewind(fp);

你成功地将文件指针重新设置到文件的开头,准备更新学生记录的数量。到目前为止一切顺利。

但后来你打电话

fwrite(&numStudents, sizeof(int), 1, fp)

实际更新记录数。并且由于文件是以附加模式打开的,因此这隐含地转换为等价于

fseek(fp, OL, SEEK_END);
fwrite(&numStudents, sizeof(int), 1, fp)

也就是说,在追加模式下,每次写入文件时,都会自动查找文件末尾,然后是您要求的写入。

因此rewind(),从长远来看,您的调用将一事无成,因为它会在下一次写入时撤消。

曾几何时,fopen使用"a"模式调用基本上只是打开文件,然后搜索到最后一次。在那些日子里,你的代码会像你预期的那样工作。但不再是了。在你的情况下,你想使用"w"mode (或者"w+"or "r+",如果你想读写),当你想在最后追加一条新记录时,调用

fseek(fp, OL, SEEK_END);

在需要时明确地到达终点。


推荐阅读