在c ++中删除文件中的结构

时间:2014-05-29 12:53:07

标签: c++

所以,这是从文件中读取每个结构的过程的代码,删除第一个找到的结构,其中的AgreementNo等于插入的int查询。然后缩短数组并重写文件。

问题是,它只是缩短了数组并删除了最后一个元素 - 好像不符合搜索标准,即使它们应该是。

(在程序开始之前,文件以+ b模式打开,所以最后,它会以这种方式重新打开。)

void deleteClient(int query, FILE *f){
  int filesize = ftell(f);
  int n = filesize/sizeof(Client);
  Client *c = new Client[n];
  Client *c2 = new Client[n-1];
  rewind(f);
  fread(c, sizeof(Client), n, f);
  for(int i=0; i<n; i++){
   if(c[i].agreementNo == query ){
    c[i] = c[n];
    break;
   }
  }
  for (int i=0; i<n-1; i++){ c2[i] = c[i]; } // reduce the size of the array ( -1 extra element)
  fclose(f);      
  remove("Client.dat");
  f = fopen("Client.dat", "w+b");
  for(int i=0;i<n-1; i++) {
  fwrite(&c2[i], sizeof(Client), 1, f);
  }
  fclose(f);
  f = fopen("Client.dat", "a+b");
}

所描述问题的原因是什么?我错过了代码中的内容吗?

2 个答案:

答案 0 :(得分:1)

我这样做:

struct MatchAgreementNo
{
  MatchAgreementNo(int agree) : _agree(agree) {}
  bool operator()(const Client& client) { return client.agreementNo == agree; }
};

void deleteClient(int query, FILE *f)
{
  int rc = fseek(f, 0, SEEK_END);
  assert(rc == 0);

  long filesize = ftell(f);
  int n = filesize / sizeof(Client);
  assert(filesize % sizeof(Client) == 0);

  Client *begin = mmap(NULL, filesize, PROT_READ|PROT_WRITE,
                              MAP_SHARED, fileno(f), 0);
  assert(begin != MAP_FAILED);
  Client *end = std::remove_if(begin, begin + n, MatchAgreementNo(query));

  rc = ftruncate(fileno(f), (end - begin) * sizeof(Client));
  assert(rc == 0);

  munmap(begin, filesize);
}

也就是说,定义一个执行所需查询的谓词函数。内存映射整个文件,以便您可以在有效的客户端阵列上应用STL算法。 remove_if()取出匹配的元素(不仅是第一个),然后我们截断文件(如果没有删除任何内容,可以是no-op)。

通过这种方式编写代码,代码是更高级别,更惯用的C ++,并且希望不那么容易出错。它也可能更快。

答案 1 :(得分:0)

代码中需要进行的一项更改是保存第一个找到的“坏”条目的索引,然后围绕该条目复制原始数组。显然,如果没有找到“坏”条目,那么你就不应该做任何事情。

一句警告:整个原始文件的阅读方法仅适用于相对较小的文件。对于较大的文件,更好的方法是打开另一个(临时)文件,以块的形式读取原始文件,然后随意复制(并在找到跳过的条目后再复制其余内容)。我想在这里有更多的优化空间,考虑到除了那一个条目,其余的文件内容保持不变。

void deleteClient(int query, FILE *f){
  int filesize = ftell(f);
  int n = filesize/sizeof(Client);
  int found = -1;
  Client *c = new Client[n];
  Client *c2 = new Client[n-1];
  rewind(f);
  fread(c, sizeof(Client), n, f);
  for(int i=0; i<n; i++){
   if(c[i].agreementNo == query ){
    printf("entry No.%d will be deleted\n", i);
    found = i;
    break;
   }
  }
  if(found == -1) return;
  if (i>0) for (int i=0; i<found; i++) { c2[i] = c[i]; } // copy the stuff before the deleted entry if it's >0
  for (int i=found+1; i<n; i++){ c2[i-1] = c[i]; } // reduce the size of the array ( -1 extra element)
  fclose(f);      
  remove("Client.dat");
  f = fopen("Client.dat", "w+b");
  for(int i=0;i<n-1; i++) {
  fwrite(&c2[i], sizeof(Client), 1, f);
  }
  fclose(f);
  f = fopen("Client.dat", "a+b");
}