You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于f_readdir实现目录文件的前后切换(支持上下按键操作)

实现目录文件的前后切换(基于f_readdir的反向浏览)

由于f_readdir本身是单向遍历目录的,要实现向前切换文件的功能,常用两种可行方案,根据你的设备内存和目录规模选择:


方案1:预缓存所有目录项(推荐小目录场景)

一次性把目录里的所有文件信息读进内存缓存,通过索引直接切换前后文件,访问速度快,不用反复操作目录。

实现思路

  1. 初始化时调用f_readdir遍历整个目录,将有效文件(跳过.和..)的信息存入数组或链表
  2. 维护一个当前文件的索引变量,按下键时索引+1,上键时索引-1(做边界判断,避免越界)
  3. 直接从缓存中取出对应索引的文件名即可

代码示例

#include "ff.h"
#include <string.h>

// 定义目录项缓存结构
typedef struct {
    char fname[256];
    FILINFO fno;
} DirItem;

// 根据实际需求调整缓存大小
DirItem dir_cache[100];
int cache_count = 0;
int current_idx = -1;

// 预加载目录缓存
void load_dir_cache(const char* dir_path) {
    DIR dir;
    FILINFO fno;
    cache_count = 0;
    current_idx = -1;

    if (f_opendir(&dir, dir_path) != FR_OK) return;

    while (f_readdir(&dir, &fno) == FR_OK && fno.fname[0] != 0) {
        // 跳过当前目录和上级目录
        if (strcmp(fno.fname, ".") == 0 || strcmp(fno.fname, "..") == 0) {
            continue;
        }
        // 存入缓存
        strcpy(dir_cache[cache_count].fname, fno.fname);
        dir_cache[cache_count].fno = fno;
        cache_count++;
    }
    f_closedir(&dir);

    // 默认选中第一个文件
    if (cache_count > 0) current_idx = 0;
}

// 获取上一个文件
const char* get_prev_file() {
    if (cache_count == 0 || current_idx <= 0) {
        return NULL; // 已是第一个文件或无文件
    }
    current_idx--;
    return dir_cache[current_idx].fname;
}

// 获取下一个文件
const char* get_next_file() {
    if (cache_count == 0 || current_idx >= cache_count - 1) {
        return NULL; // 已是最后一个文件或无文件
    }
    current_idx++;
    return dir_cache[current_idx].fname;
}

方案2:反向遍历(适合大目录场景)

如果目录文件太多,缓存占用内存过高,可以每次按上键时重新扫描目录,找到当前文件的前一个文件。

实现思路

  1. 维护当前文件名的变量
  2. 按上键时,重新打开目录,从头调用f_readdir遍历,记录当前文件的前一个文件信息
  3. 遍历到当前文件时停止,返回之前记录的文件名
  4. 注意边界处理(当前是第一个文件时,上键无效)

代码示例

#include "ff.h"
#include <string.h>

char current_fname[256] = {0};

// 获取上一个文件
const char* get_prev_file(const char* dir_path) {
    if (current_fname[0] == 0) return NULL; // 无当前文件

    DIR dir;
    FILINFO fno;
    char prev_fname[256] = {0};
    int found_current = 0;

    if (f_opendir(&dir, dir_path) != FR_OK) return NULL;

    while (f_readdir(&dir, &fno) == FR_OK && fno.fname[0] != 0) {
        if (strcmp(fno.fname, ".") == 0 || strcmp(fno.fname, "..") == 0) {
            continue;
        }
        if (found_current) break; // 已找到当前文件的前一个,退出遍历
        if (strcmp(fno.fname, current_fname) == 0) {
            found_current = 1;
        } else {
            strcpy(prev_fname, fno.fname);
        }
    }
    f_closedir(&dir);

    if (found_current && prev_fname[0] != 0) {
        strcpy(current_fname, prev_fname);
        return current_fname;
    }
    return NULL; // 已是第一个文件
}

// 获取下一个文件(保留原f_readdir逻辑)
const char* get_next_file(const char* dir_path) {
    static DIR dir;
    static int dir_opened = 0;
    FILINFO fno;

    if (!dir_opened) {
        if (f_opendir(&dir, dir_path) != FR_OK) return NULL;
        dir_opened = 1;
        // 跳过.和..
        while (f_readdir(&dir, &fno) == FR_OK && fno.fname[0] != 0) {
            if (strcmp(fno.fname, ".") != 0 && strcmp(fno.fname, "..") != 0) {
                strcpy(current_fname, fno.fname);
                return current_fname;
            }
        }
        dir_opened = 0;
        return NULL;
    } else {
        while (f_readdir(&dir, &fno) == FR_OK && fno.fname[0] != 0) {
            if (strcmp(fno.fname, ".") != 0 && strcmp(fno.fname, "..") != 0) {
                strcpy(current_fname, fno.fname);
                return current_fname;
            }
        }
        dir_opened = 0;
        return NULL;
    }
}

注意事项

  • 缓存法适合文件数量少的目录,访问速度快,但如果目录内容动态变化(比如外部修改了目录),需要重新调用load_dir_cache刷新缓存
  • 反向遍历法不占额外内存,但每次上键都要重新扫描目录,速度稍慢,适合大目录场景
  • 可根据需求添加循环浏览逻辑(比如到最后一个文件时按下键回到第一个,第一个文件按上键到最后一个)

内容的提问来源于stack exchange,提问作者N N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:38:20