正在更新包含c语言结构的二进制文件,偏移量更改会损坏文件的其余部分



我试图写一个方法,给定一个包含值更新或追加的文件,将更新第二个二进制文件。

显然,当我覆盖二进制文件中的结构体时,偏移量以某种方式改变,并且损坏了它之后的所有内容。我做错了什么,有没有一种方法来防止这种情况,而不截断和追加到文件?

当前代码:

typedef struct{
int number;
double price;
} stock;

void update(char* updatefile, char* binfile){
    FILE *fin, *fout;
    stock *currStock;
    stock *updateStock;
    int currPos;
    int update;
    int val1=0; double val2=0;
    currStock = malloc(sizeof(stock));
    updateStock = malloc(sizeof(stock));
    fin=fopen(updatefile,"r");
    while (fscanf(fin, " n%d %lf",&val1,&val2) != EOF) {
        currStock->number = val1;
        currStock->price = val2;
        printf("Updating file with stock: %d,%1.2lfn",currStock->number,currStock->price);
        fout = fopen(binfile,"r+b");
        update = 0;
        while(fread((void*)updateStock,sizeof(stock),1,fout)==1&&!update){
            printf("position: %ldn",ftell(fout));
            printf("update stock: %d, %1.2lfn",updateStock->number,updateStock->price);
            if(updateStock->number==currStock->number){ //&&updateStock->price!=currStock->price
                printf("updating stock with new price: %1.2lfn",currStock->price);
                currPos = ftell(fout);
                printf("ftell = %dn",currPos);
                fseek(fout,currPos-sizeof(stock),SEEK_SET);
                printf("ftell after seek: %ldn",ftell(fout));
                fwrite(currStock,sizeof(stock),1,fout);
                //fseek(fout,sizeof(stock),SEEK_CUR);
                update = 1;
            }
        }
        if(!update){
            fseek(fout,0,SEEK_END);
            fwrite(currStock,sizeof(stock),1,fout);
        }
        if(fclose(fout)){
            printf("value updatedn");
        }
    }
    if(!feof(fin)){
        printf("Error reading from file. Please check file formatn");
        exit(0);
    }
    if(fclose(fin)){
        puts("Error closing update file");
    }
    printf("File updated.n");
    free(currStock);
    free(updateStock);
    return;
}

输出:(使用另一种方法显示二进制文件内容)

stock in file: 1, 2.50
stock in file: 2, 5.43
stock in file: 3, 12.32
stock in file: 4, 0.54
stock in file: 5, 7.23
Updating file with stock: 2,3.40
position: 16
update stock: 1, 2.50
position: 32
update stock: 2, 5.43
updating stock with new price: 3.40
ftell = 32
ftell after seek: 16
Updating file with stock: 4,6.50
position: 16
update stock: 1, 2.50
position: 32
update stock: 2, 3.40
position: 48
update stock: 2, 5.43
position: 64
update stock: 1088, -41614952599525078000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00
position: 80
update stock: 1343, 0.00
Updating file with stock: 7,6.12
position: 18
update stock: 1, 2.50
position: 34
update stock: 2, 3.40
position: 50
update stock: 2, 5.43
position: 66
update stock: 1088, -41614952599525078000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00
position: 82
update stock: 1343, 0.00
File updated.
stock in file: 1, 2.50
stock in file: 2, 3.40
stock in file: 2, 5.43
stock in file: 1088, -41614952599525078000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00
stock in file: 1343, 0.00

edit:我知道这不是最有效的更新文件的方法(每次更新打开一个关闭),但是我想在我修复算法之前弄清楚为什么它会损坏它。

edit2:让它使用截断和追加工作,但我仍然想知道为什么这不起作用。

看起来问题发生的原因是您在使用模式r+打开的文件执行写操作后直接执行读操作。《C In a Nutshell》一书中写道:

如果模式字符串包含加号,则该模式允许输入和输出,并且必须在读取和写入文件之间同步文件位置指示符。通过在写入之后和读取之前调用fflush()或文件定位函数——fseek()、fsetpos()或rewind(),以及在读取之后和写入之前调用文件定位函数(除非确定已经读取到文件的末尾)来实现这一点。

问题出在你嵌套最多的while()循环中:

/*** Read occurs here... ***/
while(fread((void*)updateStock,sizeof(stock),1,fout)==1&&!update){  
    printf("position: %ldn",ftell(fout));
    printf("update stock: %d, %1.2lfn",updateStock->number,updateStock->price);
    if(updateStock->number==currStock->number){
        printf("updating stock with new price: %1.2lfn",currStock->price);
        currPos = ftell(fout);
        printf("ftell = %dn",currPos);
        fseek(fout,currPos-sizeof(stock),SEEK_SET);
        printf("ftell after seek: %ldn",ftell(fout));
        /** Write occurs here but...
            during the next while() check a read is immediately performed. **/
        fwrite(currStock,sizeof(stock),1,fout);
        update = 1;
    }

我在你的fwrite()之后立即添加了以下内容,它似乎正在工作…

fflush(fout);

还有,这只是一个旁注。你的currPos是一个int类型,ftell()返回一个long类型(不能保证你的int类型会保存一个long类型的值)。

希望有帮助!

相关内容

  • 没有找到相关文章

最新更新