本帖最后由 phy1335 于 2024-6-30 23:38 编辑
一、参考 二、原理 参考帖子使用一个单独的数组存储当前查找索引,在返回上级时通过循环跳过已经找过的项目,这样就可以不使用递归而遍历全部内容。 查看FileX的这两个函数fx_directory_first_full_entry_find和fx_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 - 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; }
这里就不放图,可以自行调试查看 三、实现细节 根据前面的结果,可以建立两个数组,分别保存对应不同深度的fx_path_current_entry和directory_size。返回上级时,将这两个变量设置为先前保存的值,再进行find_next就可跳过已经搜索过的内容。
[C] 纯文本查看 复制代码 uint32_t *current_search_index = NULL; // 对应不同深度的条目的索引
uint64_t *current_search_size = NULL; // 对应不同深度的条目的大小
这里使用了传入工作区指针拆分作为这两个数组,也可以直接定义两个数组。注意:如果不保存directory_size,那么进入子目录后,无法返回或者无法显示子目录下的内容。上述变量在FileX里的命名很长,不容易找。
使用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];
上述三个临时临时保存的数组是通过传入的工作区保存的。注意:经过测试,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}; // 对应不同深度的条目是否是最后一个
这个函数使用了一个时间测量函数 [C] 纯文本查看 复制代码 #ifdef PRINT_TOTAL_TIME
#include "GetRunTime.h"
#endif
如果不需要,就不要定义 PRINT_TOTAL_TIME 如果使用UTF-8,打印的树状图更加美观,定义如下的宏。要确保IDE和串口终端都使用UTF-8 [C] 纯文本查看 复制代码 #define _USE_UTF8_ // 使用UTF-8打印目录树,更美观 下面是一个实例代码 [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
代码包含很多注释了,有问题在下面交流吧!
|