обновление двоичного файла, содержащего структуры в 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.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; } 

output: (используя другой метод для отображения содержимого двоичного файла)

 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 в двух словах» говорится:

Если строка режима содержит знак плюса, тогда режим позволяет вводить и выводить, и вы должны синхронизировать индикатор положения файла между чтением и записью в файл. Сделайте это, вызвав функцию 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; } в /*** 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 будет содержать длинное значение).

Надеюсь, это поможет!