更新包含c中结构的二进制文件,更改为损坏文件的其余部分的偏移量

时间:2013-05-01 22:20:33

标签: c updates binaryfiles overwrite

我正在尝试编写一个方法,在给定包含要更新或追加的值的文件的情况下,将更新第二个二进制文件。

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

当前代码:

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.2lf\n",currStock->number,currStock->price);
        fout = fopen(binfile,"r+b");
        update = 0;
        while(fread((void*)updateStock,sizeof(stock),1,fout)==1&&!update){
            printf("position: %ld\n",ftell(fout));
            printf("update stock: %d, %1.2lf\n",updateStock->number,updateStock->price);
            if(updateStock->number==currStock->number){ //&&updateStock->price!=currStock->price

                printf("updating stock with new price: %1.2lf\n",currStock->price);
                currPos = ftell(fout);
                printf("ftell = %d\n",currPos);
                fseek(fout,currPos-sizeof(stock),SEEK_SET);
                printf("ftell after seek: %ld\n",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 updated\n");
        }
    }
    if(!feof(fin)){
        printf("Error reading from file. Please check file format\n");
        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

编辑:我知道这不是更新文件的最有效方式(打开每个更新的结束时间),但我想弄清楚为什么在修复算法之前它会破坏它。

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

1 个答案:

答案 0 :(得分:3)

看起来问题正在发生,因为您在使用模式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: %ld\n",ftell(fout));
    printf("update stock: %d, %1.2lf\n",updateStock->number,updateStock->price);
    if(updateStock->number==currStock->number){

        printf("updating stock with new price: %1.2lf\n",currStock->price);
        currPos = ftell(fout);
        printf("ftell = %d\n",currPos);
        fseek(fout,currPos-sizeof(stock),SEEK_SET);
        printf("ftell after seek: %ld\n",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值)。

希望有所帮助!