我试图写一个方法,给定一个包含值更新或追加的文件,将更新第二个二进制文件。
显然,当我覆盖二进制文件中的结构体时,偏移量以某种方式改变,并且损坏了它之后的所有内容。我做错了什么,有没有一种方法来防止这种情况,而不截断和追加到文件?
当前代码: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类型的值)。
希望有帮助!