首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从c++文件中删除结构

从c++文件中删除结构
EN

Stack Overflow用户
提问于 2014-05-29 12:53:06
回答 2查看 588关注 0票数 0

因此,下面是从文件中读取每个结构的过程代码,删除具有与插入的int查询相等的AgreementNo的第一个找到的结构。然后,它缩短数组并重写文件。

问题是,它只是缩短了数组,并删除了最后一个元素--就好像搜索准则没有得到满足一样,尽管它们应该满足。

(在过程开始之前,文件是以a+b模式打开的,因此在最后以这种方式重新打开。)

代码语言:javascript
运行
复制
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");
}

造成上述问题的原因是什么?我是不是漏掉了密码里的东西?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-05-29 13:18:13

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

一个警告词:读取原始文件作为一个整体的方法只适用于相对较小的文件。对于较大的文件,一种更好的方法是打开另一个(临时)文件,以块的形式读取原始文件,然后在执行过程中复制它(在找到跳过的条目之后,只复制其余的内容)。我想这里还有更多的优化空间,考虑到除了这一个条目之外,其余的文件内容都保持不变。

代码语言:javascript
运行
复制
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");
}
票数 0
EN

Stack Overflow用户

发布于 2014-05-29 13:29:19

我会这样做的:

代码语言:javascript
运行
复制
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()取出匹配的元素(不仅仅是第一个),然后我们截断文件(如果没有删除任何内容,这可能是一个无操作)。

通过这样编写它,代码是更高层次的,更地道的C++,希望不那么容易出错。可能也更快。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23933802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档