簡體   English   中英

c中的remove()不起作用

[英]remove() in c doesn't work from function

我試圖刪除一個文件,然后從一個不起作用的函數重命名已刪除文件名稱中的臨時文件。 請幫我

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;
    }
}

當我從另一個函數調用它時,此函數不起作用,但從主函數可以正常工作。

您的代碼中存在多個問題:

  • 您不檢查fopen()成功打開了文件。

  • 連接字符串以計算權限文件時,不會阻止潛在的緩沖區溢出。

  • 您應該將數組大小傳遞給fscanf以防止潛在的緩沖區溢出。

  • 您應該使用strerror(errno)輸出有意義且信息豐富的錯誤消息,以及失敗原因。

  • 復制權限文件的循環不正確: 為什么“while(!feof(file))”總是錯誤的?

  • 即使您無法重命名但仍設法刪除原始文件,您也會刪除重復的文件:兩個文件都可能丟失。 相反,如果重命名操作成功,則刪除重復文件是多余的。

以下是如何改進代碼:

#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()可能無法將重復文件從當前目錄移動到該目錄。 如果這是失敗的原因,則應使用適當的診斷運行代碼。
    printf(" %d ", remove(old_file_name));
    rename("duplicate.txt", old_file_name);
    remove("duplicate.txt");

此代碼大多是冗余的。 沒有必要刪除 old_file_namerename將會 old_file_name它。 (事實證明這是一個POSIX的東西,C標准不保證它)。 沒有必要刪除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) );
    }

您需要檢查每個文件操作 這包括fopenfscanf

此外,您可能會將文件向后移動。 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);
        }
    }

此代碼存在問題。 如上所述,它無法檢查fopenfscanf是否成功。 使用fscanf是一個問題,如果它無法匹配,它不會使文件指針前進。 你可以一遍又一遍地閱讀同一行,每次都失敗。 通常,請避免使用fscanfscanf

相反,用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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM