在二进制文件C中编辑记录

在二进制文件C中编辑记录,c,structure,binaryfiles,C,Structure,Binaryfiles,我正在做一个C项目,关于二进制文件中记录的CRUD操作。 记录使用的是结构数据类型 我在更新记录时遇到问题。以下是函数: void modifyGoods(char fileName[]) { struct myGood newGood; int idNumber, found = 0; printf("\nUPDATING THE RECORD..."); printf("\nEnter the id of the re

我正在做一个C项目,关于二进制文件中记录的CRUD操作。 记录使用的是结构数据类型

我在更新记录时遇到问题。以下是函数:

void modifyGoods(char fileName[]) {

     struct myGood newGood;
     int idNumber, found = 0;

     printf("\nUPDATING THE RECORD...");
     printf("\nEnter the id of the record you would like to update: ");
     scanf("%d", &idNumber);

     FILE* filePointer = fopen(fileName, "rb+");

     while ((fread(&newGood, sizeof(newGood), 1, filePointer)) > 0 && found == 0) {
         if (newGood.id == idNumber) {

// new data of the record
             printf("\nEnter the new data:\n");

             printf("Category: ");
             scanf("%s", &newGood.category);

             printf("Description: ");
             scanf("%s", &newGood.description);

             printf("Price: ");
             scanf("%f", &newGood.price);

             printf("Quantity: ");
             scanf("%d", &newGood.quantity);

// go one record back in order to overwrite the record that needs to be updated
             fseek(filePointer, -(long)sizeof(newGood), SEEK_CUR);
//overwrites record
             fwrite(&newGood, sizeof(newGood), 1, filePointer);
             
             printf("Record updated!\n");
             found = 1;
             printf("%d", found);

         }
     }

     fclose(filePointer);
     if (found == 0) {
         printf("\nERROR! THIS ID DOESN'T EXIST!\n\n");
     }

}
如果我更新二进制文件的第一条记录,它将按预期工作,但如果我尝试更新第一条记录之后的任何记录,则会发生以下情况:

A B C-二进制文件中的记录

如果我尝试更新B,那么它将变成:A B(更新的)B(旧记录)

记录得到更新,但他之后的记录被第二个记录的旧值覆盖

我应该如何处理这个问题?我更改了fseek函数的偏移量,但仍然不起作用

谢谢,, 马可首先

你怎么知道scanf成功了?如果用户刚刚按下enter键,您是否愿意接受定义时出现在
idNumber
中的任何值

测试每个返回代码。唯一可以安全忽略的是关闭文件时。(这几乎从未发生过,如果发生了,你能做什么?)

我不确定你的程序出了什么问题,但我有两个建议可能会有所帮助

  • 在调用fread之前,使用ftell(3)记录位置,而不是返回某个固定距离。然后,当您想要覆盖记录时,查找到记录的位置。这样,如果记录大小改变(或者你一开始猜错了),逻辑仍然有效

  • 使用中断而不是布尔值退出循环。你的教授可能会说这不是结构化代码,但你的同事不会介意的

  • 您可以通过切换到
    for
    循环来添加ftell:

    size_t len;
    for( off_t pos=ftell(filePointer); 
         (len = fread(&newGood, sizeof(newGood), 1, filePointer)) == sizeof(newGood; 
         pos=ftell(filePointer) ) {
      ...
      if( -1 == fseek(filePointer, pos, SEEK_SET) ) {
        err(EXIT_FAILURE, "could not seek");
      }
      if (newGood.id != idNumber) {
         continue;
      } 
    
      //overwrites record
      if( sizeof(newGood) != fwrite(&newGood, sizeof(newGood), 1, filePointer) ) {
        err(EXIT_FAILURE, "could not write");
      }
             
      printf("Record updated!\n");
      found = 1;
      printf("%d", found);
      break;
    }
    

    还有一点:当退出循环时,假设find为0,则未找到记录fread(3)会在出错时返回0,导致循环退出,在这种情况下,告诉用户记录不在那里会有点误导。

    只有当
    fseek()
    失败时才会发生这种情况。我不知道除此之外还会发生什么,但您将以这种方式读取两条记录。在第一个循环之后,它将首先再次读取,然后停止,因为找到了!=0.@EmanuelP
    found==0
    意味着继续,而不是停止。切换while循环的条件以避免额外的
    fread()
    ——现在它在检查
    found
    之前执行读取,因此在
    found
    更改后执行一次额外读取,即使它不再进入循环体。不过,这可能是无害的,因为在额外读取之后,您所做的就是关闭文件。
    size_t len;
    for( off_t pos=ftell(filePointer); 
         (len = fread(&newGood, sizeof(newGood), 1, filePointer)) == sizeof(newGood; 
         pos=ftell(filePointer) ) {
      ...
      if( -1 == fseek(filePointer, pos, SEEK_SET) ) {
        err(EXIT_FAILURE, "could not seek");
      }
      if (newGood.id != idNumber) {
         continue;
      } 
    
      //overwrites record
      if( sizeof(newGood) != fwrite(&newGood, sizeof(newGood), 1, filePointer) ) {
        err(EXIT_FAILURE, "could not write");
      }
             
      printf("Record updated!\n");
      found = 1;
      printf("%d", found);
      break;
    }