FatFs 的 f_unlink() 执行后文件仍未删除,如何排查?
程序执行到断点时,只能确认它已到达该位置,无法确认 f_unlink() 是否成功删除了文件。先在函数返回后检查 FRESULT,再对同一路径调用 f_stat(),确认文件是否存在。原问题没有提供返回值、调用代码或 FatFs 配置,暂时无法确定具体原因。
先检查函数返回值
将断点设在 f_unlink() 调用之后,查看返回值。如果断点设在调用语句本身,程序停住时函数可能尚未执行。
FR_OK 表示接口报告操作成功;其他返回值需要分别处理。程序继续运行并不代表删除成功。参见 FatFs 返回码说明。
下面的示例假设目标卷已经挂载,目标文件已经关闭,且没有其他任务同时操作该文件。使用时请将示例路径替换为实际目标路径。
#include "ff.h"
#include <stdio.h>
void check_unlink(void)
{
const TCHAR path[] = _T("0:/test.txt");
FILINFO info;
FRESULT result;
result = f_stat(path, &info);
printf("Before: f_stat = %d\n", (int)result);
if (result != FR_OK) {
return;
}
result = f_unlink(path);
printf("f_unlink = %d\n", (int)result);
if (result != FR_OK) {
return;
}
result = f_stat(path, &info);
printf("After: f_stat = %d\n", (int)result);
}
如果工程没有接入 printf() 输出,可以在 IAR 中单步执行并观察 result。删除前后检查的是同一个路径,便于排查检查对象是否一致。
根据返回码缩小范围
| 返回码 | 排查方向 |
|---|---|
FR_NO_FILE | 指定目录下没有该文件,核对文件名及目标卷。 |
FR_NO_PATH | 路径中的某个目录不存在。 |
FR_INVALID_NAME | 检查文件名格式、编码及长文件名配置。 |
FR_DENIED | 检查目标是否具有只读属性;若目标实际是目录,还要检查是否非空或为当前目录。 |
FR_LOCKED | 文件共享控制拒绝操作,检查目标是否仍被打开。 |
FR_WRITE_PROTECTED | 检查介质或驱动报告的写保护状态。 |
FR_DISK_ERR | 检查底层 disk_read()、disk_write() 或 disk_ioctl() 的错误。 |
FR_NOT_READY | 检查介质是否就绪及底层初始化状态。 |
这些返回码的具体含义可对照 官方返回码文档,避免把所有失败都归因于 IAR。
核对路径,并关闭目标文件
调试时优先使用包含逻辑驱动器和根目录的完整路径,例如 0:/logs/test.txt,同时确认创建、删除和检查文件时使用的是同一个卷。省略驱动器或使用相对路径时,实际目标取决于配置以及当前驱动器、当前目录的状态。参见 FatFs 路径规则。
删除前还应确认所有相关文件句柄都已通过 f_close() 成功关闭,并停止其他任务对目标文件的访问。FatFs 不允许删除仍然打开的文件;启用文件锁定功能时会拒绝相关操作,未启用时则可能损坏文件系统。只读属性 AM_RDO 也会导致删除被拒绝。参见 f_unlink() 官方说明。
返回 FR_OK,但文件看起来仍然存在怎么办?
先区分文件是在设备内部仍可访问,还是只在外部查看时仍然显示。
- 删除后立即对同一路径调用
f_stat()。返回FR_NO_FILE,说明该次查询没有找到文件;返回FR_OK,说明查询时文件存在。其他错误不能作为删除成功的证据。参见 f_stat() 官方说明。 - 排除文件被重新创建。暂停日志写入、初始化文件创建等相关任务,观察删除之后是否又执行了创建同名文件的代码。
- 核对外部查看结果。如果设备内部已经查不到文件,但电脑仍显示该文件,检查是否查看了同一介质、同一分区,并在设备停止访问、介质安全交接后重新读取目录。
- 检查写入是否真正完成。如果重新接入介质后文件又出现,应检查底层驱动是否正确完成写入及缓存同步。
disk_ioctl(..., CTRL_SYNC, ...)必须确保待处理写入完成;存在写回缓存时,需要将脏数据提交到介质,不能仅返回成功。参见 disk_ioctl() 官方说明。
进一步定位需要提供实际的 f_unlink() 返回值、传入路径、文件打开与关闭代码,以及删除后同一路径的 f_stat() 结果。这些信息可以帮助判断应继续检查调用方式、文件状态还是存储驱动。
备注:内容仅供参考。
