2

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

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

当前代码:

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

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

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

4

1 回答 1

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 值)。

希望有帮助!

于 2013-05-03T18:10:53.747 回答