硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1990|回复: 2
收起左侧

[FileX] 使用FileX遍历文件,打印目录树

[复制链接]

1

主题

27

回帖

30

积分

新手上路

积分
30
发表于 2024-6-30 23:31:54 | 显示全部楼层 |阅读模式
本帖最后由 phy1335 于 2024-6-30 23:38 编辑

一、参考
二、原理
参考帖子使用一个单独的数组存储当前查找索引,在返回上级时通过循环跳过已经找过的项目,这样就可以不使用递归而遍历全部内容。
查看FileX的这两个函数fx_directory_first_full_entry_findfx_directory_next_full_entry_find(主要是这个),有几点发现:
  • 1、fx_directory_first_full_entry_find将变量fx_path_current_entry设置为0
fx_directory_first_full_entry_find.c  [Line32]
   /* Set the current entry to 0 in order to pickup the first entry.  */
media_ptr ->fx_media_default_path.fx_path_current_entry = 0;


然后调用函数_fx_directory_next_full_entry_find 查找第一项
  • 2、fx_directory_next_full_entry_find则没有上述过程,直接调用函数_fx_directory_next_full_entry_find查找下一项。
  • 3、每查找一项,fx_path_current_entry会自增,增加的量不是定值。通过实验可以发现,修改这个值能直接影响后续的查找。
查找一项后增加了2
捕获.PNG 捕获2.PNG
  • 4、每次查找时如果fx_path_current_entry为0,会计算directory_size;不为0,直接读取上一次保存的directory_size
fx_directory_next_full_entry_find  [Line228]
           /* Determine the directory size. */
           if (path_ptr -> fx_path_current_entry !=  0)
           {
                /* Pickup the previously saveddirectory size.  */
                directory size =  search_dir_ptr -> fx_dir_entry_file_size;
           }

这里就不放图,可以自行调试查看
三、实现细节
  • 1、保存索引
根据前面的结果,可以建立两个数组,分别保存对应不同深度的fx_path_current_entrydirectory_size。返回上级时,将这两个变量设置为先前保存的值,再进行find_next就可跳过已经搜索过的内容。
[C] 纯文本查看 复制代码
uint32_t *current_search_index = NULL;           // 对应不同深度的条目的索引
uint64_t *current_search_size = NULL;             // 对应不同深度的条目的大小

这里使用了传入工作区指针拆分作为这两个数组,也可以直接定义两个数组。注意:如果不保存directory_size,那么进入子目录后,无法返回或者无法显示子目录下的内容。上述变量在FileX里的命名很长,不容易找。


  • 2、如何查找
使用fx_directory_next_full_entry_find查找下一项,如果成功返回,再使用fx_directory_next_entry_find查找一次,看看本次找的是不是最后一项,填充这个
[C] 纯文本查看 复制代码
uint8_t *current_is_last = NULL;                  // 对应不同深度的条目是否是最后
这个不是必须的,但可以在打印树状图时,提供“是不是最后一项”的信息,从而调整打印的缩进。
[C] 纯文本查看 复制代码
/* 需要同时设置FileX内部的索引值和目录大小 */
(FX_SD_MEDIA)->fx_media_default_path.fx_path_current_entry = current_search_index[current_search_depth];
(FX_SD_MEDIA)->fx_media_default_path.fx_path_directory.fx_dir_entry_file_size = current_search_size[current_search_depth];

  • 3、输入工作区
上述三个临时临时保存的数组是通过传入的工作区保存的。注意:经过测试,32位数组不需要对齐,64位数组的地址需要对齐
工作区的最小size计算如下
[C] 纯文本查看 复制代码
size_t total_size = depth_max * (sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint64_t)); // 计算所需的总大小
total_size += sizeof(uint64_t) - (total_size % sizeof(uint64_t)); // 确保64位数组是8字节对齐的,可能需要添加填充
四、如何使用
  • 1、在文件的开头有个宏定义,将其指向为SD卡的FX_MEDIA结构体指针,后续会大量使用。比如
  • [C] 纯文本查看 复制代码
    #define FX_SD_MEDIA  (&sdio_disk)  // 放你的存储媒体结构体指针

  • 2、如果不使用动态传入工作区指针,可以修改一下全局数组或者在函数内分配数组。注意不要爆栈了!
[C] 纯文本查看 复制代码
// uint32_t current_search_index[MAX_TRAVEL_DEPTH] = {0}; // 对应不同深度的条目的索引
// uint64_t current_search_size[MAX_TRAVEL_DEPTH] = {0}; // 对应不同深度的条目的大小
// uint8_t current_is_last[MAX_TRAVEL_DEPTH] = {0};      // 对应不同深度的条目是否是最后一个
  • 3、时间测量
这个函数使用了一个时间测量函数
[C] 纯文本查看 复制代码
#ifdef PRINT_TOTAL_TIME
#include "GetRunTime.h"
#endif

如果不需要,就不要定义 PRINT_TOTAL_TIME
  • 4、使用UTF-8
如果使用UTF-8,打印的树状图更加美观,定义如下的宏。要确保IDE和串口终端都使用UTF-8
[C] 纯文本查看 复制代码
#define _USE_UTF8_ // 使用UTF-8打印目录树,更美观
  • 5、添加到你的程序,确保媒体已经正确打开
下面是一个实例代码
[C] 纯文本查看 复制代码
FX_MEDIA sdio_disk;
#define FX_SD_MEDIA (&sdio_disk)
void print_tree()
{
    uint16_t status = 0;
   
    uint8_t workspace[MAX_TRAVEL_DEPTH] = {0};

    status = fx_media_open(FX_SD_MEDIA,          // FX_MEDIA结构体
                           "STM32_SD_DISK",      // 打开后的名字
                           fx_stm32_sd_driver,   // IO驱动
                           0,                    // 自定义的信息结构体,可以在驱动里使用
                           (VOID *)sdio_buffer,  // 缓存
                           sizeof(sdio_buffer)); // 缓存大小

    if (status != FX_SUCCESS)
    {
        printf("Open SD media failed! %#X\n", status);
        return;
    }

    /* 打印根目录,深度最大为10,显示隐藏文件 */
    char *path = "/";
    status = sd_com_tree(path, 10, SD_SHOW_HIDE, workspace, sizeof(workspace));
    if (status != FX_SUCCESS)
    {
        printf("Print tree [%s] failed! %#X\n", path, status);
        return;
    }

    /* 关闭SD卡 */
    status = fx_media_close(FX_SD_MEDIA);
    if (status != FX_SUCCESS)
    {
        printf("Close SD media failed! %#X\n", path, status);
    }
}

五、效果
左边为深度1                       右边为深度2
屏幕截图 2024-06-30 230006.png 屏幕截图 2024-06-30 230140.png 屏幕截图 2024-06-30 230159.png
GetRunTime.c (621 Bytes, 下载次数: 6)


GetRunTime.h (570 Bytes, 下载次数: 3)


sd_com_tree.1.c (15.43 KB, 下载次数: 20)


代码包含很多注释了,有问题在下面交流吧!






评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116217
QQ
发表于 2024-7-1 09:04:01 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

9

主题

66

回帖

108

积分

初级会员

积分
108
发表于 2024-7-1 22:39:18 | 显示全部楼层
不错,遍历性能上会好很多
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-6-10 09:34 , Processed in 0.345601 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表