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

标签 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:使用截断和附加使其可以工作,但我仍然想知道为什么这不起作用。

最佳答案

看起来出现问题是因为您在对以 r+ 模式打开的文件执行写入操作后直接执行读取操作。 《C In a Nutshell》一书指出:

If the mode string includes a plus sign, then the mode allows both input and output, and you must synchronize the file position indicator between reading from and writing to the file. Do this by calling fflush() or a file positioning function -- fseek(), fsetpos(), or rewind() -- after writing and before reading, and by calling a file-positioning function after reading and before writing (unless it is certain that you have read to the end of the file).

问题出在您最嵌套的 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 值)。

希望有帮助!

关于c - 更新包含 c 中结构的二进制文件,偏移量更改为损坏文件的其余部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16327416/

相关文章:

C 删除字符串中的字符

c - c 中的动态内存分配会引发特定大小的错误

c - 以非选项字符开头时 getopt_long() 失败

android - 设备屏幕关闭时的应用程序更新 - 应用程序无法正常启动

python - 将C公式转换为Python

php - MYSQL - 多个表更新问题

ios - App Store 上的我的应用程序在未发布更新的情况下自行更新

matlab - 在 Matlab 中读取一个大的结构化文件

Python3,二进制数据与我需要的表示不同

python - Python中如何判断一个流是文本流还是二进制流?