所以,这是从文件中读取每个结构的过程的代码,删除第一个找到的结构,其中的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");
}
所描述问题的原因是什么?我错过了代码中的内容吗?
答案 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");
}