1

我正在处理 ac 项目,我需要从目录中删除一个文件。出于某种原因,尽管它一直说由于文件或目录不存在而无法删除。下面是我用来删除文件的代码。

void deleteOldestLog()
{
    FILE *fp;
    char path[FILE_PATH_BUF_LEN], *fileName;

    fp = popen("ls -tr /home/myfolder/logs/ |head -1", "r");
    if (fp == NULL)
    {
        printf("Failed to run command");
    }
    else
    {
        char removalPath[FILE_PATH_BUF_LEN];
        while ((fileName = fgets(path, sizeof(path)-1, fp)) != NULL)
        {
            sprintf(removalPath, "/home/myfolder/logs/%s", fileName, sizeof(fileName)-1);

            printf("Removing file: %s", removalPath);
            if (remove(removalPath) != 0)
            {
                perror("ERROR DELETING LOG");
            }
            else
            {
                printf("Successfully deleted %s", removalPath);
            }
            break;
        }
        pclose(fp);
    }
}

即使它说它找不到文件,因为它不存在,但我知道这不是真的,因为如果我运行ll后跟 c 程序打印的路径,它会返回我试图删除的文件。

我认为这可能是因为 fgets 将 '\0' 放在阻止删除工作的字符串的末尾。

我怎样才能解决这个问题?

4

1 回答 1

5

读取的文件名末尾有一个换行符fgets()。您的文件名实际上并不以换行符结尾。

您尝试使用以下方法删除换行符:

sprintf(removalPath, "/home/myfolder/%s", fileName, sizeof(fileName)-1);

但是,为了有效,您需要使用strlen()而不是sizeof(),并且您需要修改格式字符串:

sprintf(removalPath, "/home/myfolder/%.*s", (int)strlen(fileName)-1, fileName);

的参数*必须是 anintstrlen()返回 a size_t; 因此演员。(如果您打开警告,GCC 会警告这类事情;至少使用-Wall.)

给您的提示:如有疑问,请打印字符串。我通常会使用这样的格式。注意字符串周围的尖括号:

printf("Removing: <<%s>>\n", removalPath);

当你看到:

Removing: <</home/myfolder/something
>>

您知道字符串中的换行符有问题。如果没有标记,您可能不会注意到字符串中的换行符导致输出中出现额外的换行符。


为什么需要修改格式字符串?

我们再来看看原文sprintf()

sprintf(removalPath, "/home/myfolder/%s", fileName, sizeof(fileName)-1);

格式字符串需要 1 个参数,一个字符串。该调用提供了两个值,一个字符串和一个长度。所以,第一个问题是有一个剩余的参数。这通常不会造成损害,但请注意这一点。据推测,传递长度减一的原因是丢失了最后一个字符。系列中的格式printf()可以用一个或两个数字装饰,其中一个或两个都可以有一个*而不是一个整数值。这些数字限制了格式化值的长度。当你写:

%.*s

您声明输出的长度应int与字符串本身之前作为参数传递的值指定的长度完全相同。因此修订:

sprintf(removalPath, "/home/myfolder/%.*s", (int)strlen(fileName)-1, fileName);

(我在添加此信息时刚刚修复。)

我也没有在sprintf()etc 的输出中添加错误检查。这并不罕见;但是,最佳编码实践确实可以确保函数之类sprintf()的返回您期望的值(这是写入字符串的字符数,不包括结尾的 null '\0'

(旁白:一般来说,使用snprintf()sprintf(); 更好,可以避免缓冲区溢出。

snprintf(removalPath, sizeof(removalPath), "/home/myfolder/%.*s",
         (int)strlen(fileName)-1, fileName);

但是,*snprintf()MSVC 下的函数行为不同于 C 标准(C99、C11)规定的行为。更糟糕的是,对于 ofvsnprintf_s()和其他_s函数,MSVC 和 C 标准之间的参数列表是不同的。)

于 2012-06-20T14:02:12.197 回答