无法在文件开始时重写数据,但我可以在 C 中以追加模式在结尾处应用

Can't rewrite the data at file starting but I can apped at the End in append mode in C

我想将学生信息存储在C文件中,我选择写入二进制文件format.first我已经将所有学生数据以写模式写入文件。前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);
}

when I want to append some more student data to the file, I can apped the student data at the end of file in append mode but could not update the no of students at the start of file (first 4 bytes(int)) which are already written in write mode. There is no where stated in manpages that I can't rewrite the data that are already written in write mode.

Yes there is:

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.

来自 the Linux man page

Opening a file in append mode (a as the first character of mode) causes all subsequent write operations to this stream to occur at end-of-file, as if preceded the call:

      fseek(stream, 0, SEEK_END);

在 POSIX 系统上以追加模式打开文件但仍然能够写入文件中任何位置的唯一方法是使用 POSIX open() call with the O_APPEND flag and then use the POSIX pwrite() call 写入所需位置:

The pwrite() function shall be equivalent to write(), except that it writes into a given position and does not change the file offset (regardless of whether O_APPEND is set).

But pwrite() is broken on Linux:

POSIX requires that opening a file with the O_APPEND flag should have no effect on the location at which pwrite() writes data. However, on Linux, if a file is opened with O_APPEND, pwrite() appends data to the end of the file, regardless of the value of offset.

当你打电话时

rewind(fp);

您成功将文件指针重置为文件开头,准备更新学生记录数。到目前为止还好。

但后来你打电话给

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

实际更新记录数。由于文件是在追加模式下打开的,因此这隐含地转换为

的等价物
fseek(fp, OL, SEEK_END);
fwrite(&numStudents, sizeof(int), 1, fp)

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

因此您的 rewind() 调用在长 运行 中没有完成任何事情,因为它在下一次写入时被撤消了。

曾几何时,用"a"模式调用fopen基本上只是打开文件,然后查找一次结束。在那些日子里,您的代码会按您的预期工作。但现在不是了。在你的情况下,你想使用 "w" 模式(或者 "w+""r+",如果你想读写),当你想在末尾追加一条新记录时, 打电话

fseek(fp, OL, SEEK_END);

在需要时明确地结束。