FATFS文件系统,采用非递归的方法遍历文件夹

2019-12-20 21:35发布

本帖最后由 am3359 于 2018-1-18 17:02 编辑

//我用STM32F407+FATFS+freeRTOS搭建的系统,需要遍历存储器中每个文件夹和文件,常用的办法是递归调用,遍历函数内嵌套自己直到找到每个文件或文件夹。由于目录深度不可控,这个方法有大量的压栈和出栈容易造成栈溢出系统崩溃。
//现采用目录深度可控的非递归方法如下:

#define LEVEL          8                                       //LEVEL设置大小代表遍历的深度,8就代表8层,内存足够的话可以设置更大些
    u8 j,m;
    u8 l[LEVEL];                                               //l[]保存每层文件夹长度,返回上级目录时用
    DIR dir_a[LEVEL];                                          //FATFS使用的目录结构,只有这个比较占内存需要LEVEL*36字节
    tbuf[64];                                                  //注意tbuf的大小要能放得下最深的文件名绝对路径

    m = 0;
    j = 1;
    printf("当前目录: %s: ", tbuf);
    while(1) {
        if ( j > m ) {                                         //只有搜索子目录时才执行
            f_opendir(&dir_a[j-1], (TCHAR*)tbuf);
            l[j-1] = strlen((char *)tbuf);
        }
        m = j;
        f_readdir(&dir_a[j-1], &fileinfo);                     //读取当前目录下的一个文件
        if (fileinfo.fname[0] == 0) {                          //到末尾了,退出
            if (j>1) j--;                                      //下个循环进入父目录
            else break;
            tbuf[l[j-1]] = '';                               //存储的路径返回上级目录
        } else {
            sprintf((char *)tbuf,"%s/%s",tbuf,*fileinfo.lfname ? fileinfo.lfname : fileinfo.fname);//搜索到的文件或文件名连接成完整的路径
            if (fileinfo.fattrib & AM_DIR) {                   //是目录
                printf("%s [%dD] ", tbuf,j);                //打印目录
                if (j<8) j++;                                  //下个循环进入子目录
            } else {
                printf("%s [%dF] ", tbuf,j);                //打印文件
                tbuf[l[j-1]] = '';                           //存储的路径返回目录
            }
        }
    }
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
52条回答
am3359
1楼-- · 2019-12-25 16:52
 精彩回答 2  元偷偷看……
vuo50z
2楼-- · 2019-12-25 22:40
am3359 发表于 2018-1-19 10:10
不懂,我没研究那么深啊,用了递归函数FreeRTOS就挂了,才想用非递归的办法,但是没找到 ...

void test( void )
{
        int i = 0;                        // 这个i需要保存
        char acFileName[256];        // 这个buffer不需要保存。可以定义为全局的,或者根函数申请一个然后通过参数传下来,这样就不占用堆栈了。

        while( 1 )
        {
                i ++;                                        // 本层循环计数

                GetName( acFileName );        // buffer打印完就没用了
                printf( "%s %d", acFileName, i );

                if( strlen( acFileName  ) == 0 )
                {
                        return;
                }

                test();
        }
}
vuo50z
3楼-- · 2019-12-25 23:29
vuo50z 发表于 2018-1-19 10:29
void test( void )
{
        int i = 0;                        // 这个i需要保存

上面那个函数每次递归都要占用256字节的buffer,改成下面这样,只在main中申请一个256字节就可以了。

void test( char *pcFileName )
{
        int i = 0;                        // 这个i需要保存

        while( 1 )
        {
                i ++;                                                // 本层循环计数

                GetName( pcFileName);                // buffer打印完就没用了
                printf( "%s %d", pcFileName, i );

                if( strlen( pcFileName) == 0 )
                {
                        return;
                }

                test( pcFileName );
        }
}

int main( void )
{
        char acFileName[256];        // 这个buffer不需要保存。可以定义为全局的,或者根函数申请一个然后通过参数传下来,这样就不占用堆栈了。

        test( acFileName );
}
am3359
4楼-- · 2019-12-26 02:03
我用下面的函数:
在FreeRTOS里运行一次系统就死了
FRESULT scan_files (char* path)
{
    FRESULT res;
    u32 i[8],j;
    char fn[64],tmppath[64];
    strcpy((char *)tmppath,(char *)path);
    for(j=0;j<8;j++) {
        res = f_opendir(&dir, (TCHAR*)tmppath);
        if (res == FR_OK) {
            i[j] = strlen(tmppath);
            {
                res = f_readdir(&dir, &fileinfo);
                if (res != FR_OK || fileinfo.fname[0] == 0) break;
                if (fileinfo.fname[0] == '.') continue;

                strcpy((char *)fn,*fileinfo.lfname ? fileinfo.lfname : fileinfo.fname);

                if (fileinfo.fattrib & AM_DIR) {//是目录
                    strcat(tmppath,"/");
                    strcat(tmppath,fn);
                    printf("%s ", tmppath);
                    res = scan_files(tmppath);
                    if (res != FR_OK) break;
                    tmppath[i[j]] = 0;
                } else {
                    printf("%s/%s ", tmppath, fn);
                }
            }
        }
    }

   return res;
}
脑子不够用,怎么改让它不死??
am3359
5楼-- · 2019-12-26 06:30
fn[64],tmppath[64]重复分配太多了造成溢出?
myxiaonia
6楼-- · 2019-12-26 06:52
 精彩回答 2  元偷偷看……

一周热门 更多>