我正在处理一个c项目,我需要从目录中删除一个文件。出于某种原因,虽然它继续说它无法删除,因为文件或目录不存在。下面是我用来删除文件的代码。
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'放在字符串的末尾,这会阻止删除工作。
我该如何解决这个问题?
答案 0 :(得分:5)
fgets()
读取的文件名末尾有换行符。您的文件名实际上并不以换行符结尾。
您尝试使用以下内容删除换行符:
sprintf(removalPath, "/home/myfolder/%s", fileName, sizeof(fileName)-1);
但是,为了有效,您需要使用strlen()
而不是sizeof()
,并且您需要修改格式字符串:
sprintf(removalPath, "/home/myfolder/%.*s", (int)strlen(fileName)-1, fileName);
*
的参数必须是int
,strlen()
返回size_t
;因此演员。 (如果你打开警告,海湾合作委员会会警告这类事情;至少使用-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()
等的输出中。这并不罕见;但是,最佳编码实践确保像sprintf()
这样的函数返回您期望的值(这是写入字符串的字符数,不包括尾随空'\0'
。
(旁白:一般来说,最好使用snprintf()
而不是sprintf()
;这样可以避免缓冲区溢出。
snprintf(removalPath, sizeof(removalPath), "/home/myfolder/%.*s",
(int)strlen(fileName)-1, fileName);
但是,MSVC下*snprintf()
函数的行为与C标准(C99,C11)规定的行为不同。更糟糕的是,在vsnprintf_s()
和其他_s
函数的情况下,参数列表在MSVC和C标准之间是不同的。)