我尝试删除一个文件,然后从一个不起作用的函数中重命名已删除文件名称中的临时文件。请帮帮我
boolean delete_user(char user_name[256]) //only for Admin
{
boolean status = FALSE;//what does the function return
User_Data *ud = NULL;
boolean found_user = FALSE;
FILE *new_file = NULL;
FILE *fp = NULL;
char user_name_to_copy[256];
char password_to_copy[256];
char old_file_name[256];
ud = find_user(user_name);
if (ud == NULL) {
printf("The username wasn't found!\n");
return FALSE;
}
if (!strcmp(ud->permission_type, "Admin")) {
printf("Cant delete an admin.");
return FALSE;
} else {
// the user to delete was found
new_file = fopen("duplicate.txt", "wt");
strcpy(old_file_name, ud->permission_type);
strcat(old_file_name, "s.txt"); //the name of the file is in plural and ends with .txt
fp = fopen(old_file_name, "rt");
while (!feof(fp)) {
//copy all the users except the user to delete the new file
fscanf(fp, "%s %s\n", user_name_to_copy, password_to_copy);
if (strcmp(user_name_to_copy, user_name)) {
fprintf(new_file, "%s %s\n", user_name_to_copy, password_to_copy);
}
}
fclose(fp);
fclose(new_file);
printf(" %d ", remove(old_file_name));
rename("duplicate.txt", old_file_name);
remove("duplicate.txt");
return TRUE;
}
}
当我从另一个函数调用它时,此函数不起作用,但从主函数可以正常工作。
答案 0 :(得分:2)
您的代码中存在多个问题:
您不会检查fopen()
是否已成功打开文件。
连接字符串以计算权限文件时,不会阻止潜在的缓冲区溢出。
您应该将数组大小传递给fscanf
以防止潜在的缓冲区溢出。
您应使用strerror(errno)
输出有意义且信息丰富的错误消息,以及失败原因。
复制权限文件的循环不正确:Why is “while ( !feof (file) )” always wrong?
即使您无法重命名但仍设法删除原始文件,您也会删除重复的文件:这两个文件可能都会丢失。相反,如果重命名操作成功,则删除重复文件是多余的。
以下是改进代码的方法:
#include <errno.h>
#include <string.h>
boolean delete_user(char user_name[256]) { //only for Admin
boolean status = FALSE; // the function return value
User_Data *ud = NULL;
boolean found_user = FALSE;
FILE *new_file = NULL;
FILE *fp = NULL;
char user_name_to_copy[256];
char password_to_copy[256];
char old_file_name[256];
ud = find_user(user_name);
if (ud == NULL) {
printf("User '%s' was not found!\n", user_name);
return FALSE;
}
if (!strcmp(ud->permission_type, "Admin")) {
printf("Cannot delete user '%s', user has admin status.\n", user_name);
return FALSE;
}
// the user to delete was found
new_file = fopen("duplicate.txt", "wt");
if (new_file == NULL) {
printf("Cannot open file 'duplicate.txt': %s\n"
strerror(errno));
return FALSE;
}
// the name of the file is in plural and ends with .txt
snprintf(old_file_name, sizeof old_file_name, "%ss.txt", ud->permission_type);
fp = fopen(old_file_name, "rt");
if (fp == NULL) {
printf("Cannot open user file '%s': %s\n"
old_file_name, strerror(errno));
return FALSE;
}
// copy all the users except the user to delete the new file
while (fscanf(fp, "%255s %255s\n", user_name_to_copy, password_to_copy) == 2) {
if (strcmp(user_name_to_copy, user_name)) {
fprintf(new_file, "%s %s\n", user_name_to_copy, password_to_copy);
}
}
fclose(fp);
fclose(new_file);
if (remove(old_file_name)) {
printf("Error removing file '%s': %s\n",
old_file_name, strerror(errno));
remove("duplicate.txt");
return FALSE;
}
if (rename("duplicate.txt", old_file_name)) {
printf("Error renaming file 'duplicate.txt' to '%s': %s\n",
old_file_name, strerror(errno));
// keep duplicate.txt
return FALSE;
}
// duplicates.txt was successfully renamed, no need to remove it.
return TRUE;
}
注意:
rename()
可能无法将重复文件从当前目录移动到该目录。如果这是失败的原因,则应使用适当的诊断运行代码。答案 1 :(得分:1)
printf(" %d ", remove(old_file_name));
rename("duplicate.txt", old_file_name);
remove("duplicate.txt");
此代码多数是冗余的。 没有必要删除(原来这是POSIX的事情,C标准不保证)。没有必要删除old_file_name
,rename
会将其击败。duplicate.txt
,它已被重命名。
if( remove(old_file_name) != 0 ) {
fprintf( stderr, "Could not remove %s: %s", old_file_name, strerror(errno) );
}
if( rename("duplicate.txt", old_file_name) != 0 ) {
fprintf( stderr, "Could not rename %s to %s: %s", "duplicate.txt", old_file_name, strerror(errno) );
}
您需要检查 每个文件操作 。其中包括fopen
和fscanf
。
此外,您可能会将文件向后移动。这是rename( old, new )
但看起来你写的是rename( new, old )
。如果您没有将它们颠倒过来,请考虑使代码更容易理解的变量名称。
fp = fopen(old_file_name, "rt");
while (!feof(fp)) {
//copy all the users except the user to delete the new file
fscanf(fp, "%s %s\n", user_name_to_copy, password_to_copy);
if (strcmp(user_name_to_copy, user_name)) {
fprintf(new_file, "%s %s\n", user_name_to_copy, password_to_copy);
}
}
此代码存在问题。如上所述,它无法检查fopen
和fscanf
是否成功。使用fscanf
是一个问题,如果它不匹配,它不会推进文件指针。你可以一遍又一遍地阅读同一行,每次都失败。一般来说,avoid fscanf
and scanf
。
相反,请使用fgets
阅读整行,并使用sscanf
进行解析。一定要检查sscanf
是否成功,否则你会打印出胡言乱语。请注意,sscanf
限制了它将读取的字符串大小以防止缓冲区溢出。
FILE *fp = open_file(old_file_name, "rt");
char line[1024];
while (fgets(line, 1024, fp)) {
//copy all the users except the user to delete the new file
if( sscanf(fp, "%255s %255s\n", user_name_to_copy, password_to_copy) != 2 ) {
fprintf(stderr, "Couldn't understand line '%s'\n", line);
continue;
}
if (strcmp(user_name_to_copy, user_name)) {
fprintf(new_file, "%s %s\n", user_name_to_copy, password_to_copy);
}
}
fclose(fp);
由于检查文件是否打开是多余的,我建议写一个小功能来做到这一点。
FILE *open_file(char *filename, char *mode) {
FILE *fp = fopen(filename, mode);
if( fp == NULL ) {
fprintf(
stderr, "Could not open '%s' for '%s': %s\n",
filename, mode, strerror(errno)
);
exit(1);
}
return fp;
}