我正在研究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);
}
}
Run Code Online (Sandbox Code Playgroud)
即使它说它找不到文件因为它不存在我知道这不是真的,因为如果我运行ll后跟c程序打印的路径它返回我试图删除的文件.
我想这可能是因为fgets将'\ 0'放在字符串的末尾,这会阻止删除工作.
我怎样才能解决这个问题?
读取的文件名末尾有换行符fgets().您的文件名实际上并不以换行符结尾.
您尝试删除换行符:
sprintf(removalPath, "/home/myfolder/%s", fileName, sizeof(fileName)-1);
Run Code Online (Sandbox Code Playgroud)
但是,为了有效,您需要使用strlen()而不是sizeof(),并且您需要修改格式字符串:
sprintf(removalPath, "/home/myfolder/%.*s", (int)strlen(fileName)-1, fileName);
Run Code Online (Sandbox Code Playgroud)
*必须为a 的论证int并strlen()返回a size_t; 因此演员.(如果你打开警告,海湾合作委员会会警告这类事情;至少使用-Wall.)
给你的提示:如有疑问,请打印字符串.我通常会使用这样的格式.请注意字符串周围的尖括号:
printf("Removing: <<%s>>\n", removalPath);
Run Code Online (Sandbox Code Playgroud)
当你看到:
Removing: <</home/myfolder/something
>>
Run Code Online (Sandbox Code Playgroud)
你知道字符串中有换行符有问题.如果没有标记,您可能不会注意到字符串中有换行符导致输出中出现额外的换行符.
为什么需要修改格式字符串?
让我们再看一下原作sprintf():
sprintf(removalPath, "/home/myfolder/%s", fileName, sizeof(fileName)-1);
Run Code Online (Sandbox Code Playgroud)
格式字符串需要1个参数,一个字符串.该调用提供两个值,一个字符串和一个长度.所以,第一个问题是有一个遗留的论点.这通常没有损坏,但要注意它.据推测,传递长度减去一的原因是失去最后一个角色.系列中的格式printf()可以用一个或两个数字装饰,其中一个或两个都可以有一个*而不是整数值.这些数字限制格式化值的长度.当你写:
%.*s
Run Code Online (Sandbox Code Playgroud)
您声明输出的长度应该是int在字符串本身之前作为参数传递的值指定的长度.因此修订:
sprintf(removalPath, "/home/myfolder/%.*s", (int)strlen(fileName)-1, fileName);
Run Code Online (Sandbox Code Playgroud)
(我刚刚在添加此信息时修复了这个问题.)
我也没有将错误检查添加到输出sprintf()等等.这并不罕见; 但是,最佳编码实践确保函数sprintf()返回您期望的值(这是写入字符串的字符数,不包括尾随空值'\0'.
(旁白:一般来说,使用snprintf()比它更好sprintf();这可以避免缓冲区溢出.
snprintf(removalPath, sizeof(removalPath), "/home/myfolder/%.*s",
(int)strlen(fileName)-1, fileName);
Run Code Online (Sandbox Code Playgroud)
但是,*snprintf()MSVC 下的功能行为与C标准(C99,C11)规定的行为不同.更糟糕的是,在vsnprintf_s()其他_s函数和其他函数的情况下,参数列表在MSVC和C标准之间是不同的.)