运行 很好,但重命名 () 不起作用

Running is fine but rename() does not work

通过创建一个临时文本文件来从文本文件中删除一行的简单功能代码,该文件将在删除该行后存储新内容并替换旧内容Storage.txt 文件与临时文件。

delete() 函数有效,但我唯一的问题似乎是 rename() 函数似乎无法按预期运行。

代码

void delete() {
    struct task task;
    FILE *fp;
    char str[100];
    char ch;
    int delete_line = 0;
    fp = fopen("Storage.txt", "r");
    if (fp == NULL) {
        printf("Error opening file");
        fopen("Storage.txt", "w");
        exit (1);
    }
    printf("\n\n\nAll Tasks\n");
    printf("----------\n\n");
    do {
        ch = fgetc(fp);
        printf("%c", ch);
    } while (ch != EOF);
    fclose(fp);
    int line_no,ret;
    char filename[] = "Storage.txt";
    char newname[] = "temp.txt";
    FILE *file, *temp;
    file = fopen("Storage.txt", "r");
    temp = fopen("temp.txt", "w");
    printf("Select Line to delete: ");
    scanf("d", &delete_line);
    getchar();
    temp = fopen("temp.txt", "w");
    while (fgets(str, 99, fp) != NULL) {
        line_no++;
        if (line_no != delete_line) {
            fputs(str, temp);
        }
    }
    fclose(file);
    fclose(temp);
    remove(filename);
    ret = rename(newname, filename);
    if (ret == 0) {
        printf("File renamed successfully");
    } else {
        printf("Error: unable to rename the file");
    }
}

您的代码打开“temp.txt”文件两次:

temp = fopen("temp.txt", "w");
...
temp = fopen("temp.txt", "w");

并关闭一次。这将为文件留下一个打开的文件描述符,直到程序退出。

remove() 使用 unlink() 删除文件。 unlink() 的手册页说:

If the name was the last link to a file but any processes still have the file open the file will remain in existence until the last file descriptor referring to it is closed.

确保在不再需要时关闭所有文件描述符。

如果 oldpathnewpath 的文件仍然打开,rename 可能会失败。

这里的两个主要错误是:

1。 scanf("d", ...) 而不是 scanf("%d", ...)

scanf() 需要一个格式字符串来知道如何解析输入,就像 printf()(f 代表格式)需要它来知道如何构造输出一样;它们的格式字符串语法几乎相同。

2。 未初始化 line_no,这意味着它不能保证从 0/1 开始,因此它可能永远不会等于 delete_line,并且不会删除该行。

代码中存在一些问题:

  • ch 必须定义为类型 int 才能可靠地检测 EOF

  • do/while循环读取文件内容在测试之前输出EOF指标。你应该使用 while ((ch = fgetc(fp)) != EOF) putchar(ch);

  • 应避免使用标识符 delete 以避免混淆 C++ 程序员,请改用 delete_line

  • 您应该测试 fopenremove 的失败并显示错误原因。

  • 打开文件读取失败,为什么用fopen("Storage.txt", "w")创建文件?

  • 文件 temp.txt 打开了两次,这可能会阻止旧系统上的重命名操作。

  • line_no 未初始化。如果行编号从 1.

    开始,则应将其初始化为 1
  • 将行读入数组对于此任务不可靠,因为超过 99 字节的行将被计​​算多次。

这是修改后的版本:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void delete_line() {
    const char *filename = "Storage.txt";
    const char *tempname = "temp.txt";
    int ch;

    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno));
        exit(1);
    }
    printf("\n\n\nAll Tasks\n");
    printf("----------\n\n");
    while ((ch = getc(fp)) != EOF)  {
        putchar(ch);
    }
    fclose(fp);

    int delete_line = 0;
    printf("Select Line to delete: ");
    if (scanf("d", &delete_line) != 1) {
        fprintf(stderr, "invalid or missing input\n");
        exit(1);
    }
    // read and discard the rest of the user input line
    while ((ch = getchar()) != EOF && c != '\n')
        continue;

    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno));
        exit(1);
    }
    FILE *temp = fopen(tempname, "w");
    if (temp == NULL) {
        fprintf(stderr, "Cannot open file %s: %s\n", tempname, strerror(errno));
        fclose(file);
        exit(1);
    }
    int line_no = 1;
    while ((ch = getc(file)) != EOF) {
        if (line_no != delete_line)
            putc(ch, temp);
        if (ch == '\n')
            line_no++;
    }
    fclose(file);
    fclose(temp);

    if (remove(filename)) {
        fprintf(stderr, "Cannot remove %s: %s\n", filename, strerror(errno));
    } else {
        if (rename(tempname, filename)) {
            fprintf(stderr, "Cannot rename %s as %s: %s\n",
                    tempname, filename, strerror(errno));
        }
    }
}

temp = fopen("temp.txt", "w");调用两次