PAYATHON 2026

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,但文件看起来仍然存在怎么办?

先区分文件是在设备内部仍可访问,还是只在外部查看时仍然显示。

  1. 删除后立即对同一路径调用 f_stat()。返回 FR_NO_FILE,说明该次查询没有找到文件;返回 FR_OK,说明查询时文件存在。其他错误不能作为删除成功的证据。参见 f_stat() 官方说明。
  2. 排除文件被重新创建。暂停日志写入、初始化文件创建等相关任务,观察删除之后是否又执行了创建同名文件的代码。
  3. 核对外部查看结果。如果设备内部已经查不到文件,但电脑仍显示该文件,检查是否查看了同一介质、同一分区,并在设备停止访问、介质安全交接后重新读取目录。
  4. 检查写入是否真正完成。如果重新接入介质后文件又出现,应检查底层驱动是否正确完成写入及缓存同步。disk_ioctl(..., CTRL_SYNC, ...) 必须确保待处理写入完成;存在写回缓存时,需要将脏数据提交到介质,不能仅返回成功。参见 disk_ioctl() 官方说明。

进一步定位需要提供实际的 f_unlink() 返回值、传入路径、文件打开与关闭代码,以及删除后同一路径的 f_stat() 结果。这些信息可以帮助判断应继续检查调用方式、文件状态还是存储驱动。

备注:内容仅供参考。