用C语言实现的遍历目录及其子目录下所有文件

时间:2022-05-06 12:12:06
以前我在坛子里发了一个帖子
《C语言实现的获取某目录及其子目录下所有文件的绝对路径》
http://topic.csdn.net/u/20111223/00/d1148664-affb-49ce-bff1-d3bd107ffaf4.html
之前不知道使用链表,直接递归实现,结果测试的时候,程序总是会爆栈。
这些改进了,使用链表来实现,测试结果很满意。可以遍历整个磁盘。
链表的结构定义如下:
/* 定义结构体 */
typedef struct folder_node_tag
{
    char   *name_ptr;   //自己的名字
    int    name_leng;   //名字的长度
    int    is_visited;  //是否已经被访问了
    struct folder_node_tag *parent_ptr;       //其父
    struct folder_node_tag *prev_brother_ptr; //其兄
    struct folder_node_tag *next_brother_ptr; //其弟
    struct folder_node_tag *first_child_ptr;  //长子
}FOLDER_NODE_T;
/* 搜索时下一步的定义 */
typedef enum next_find_action_e
{
NFA_IS_ENTRY_SUBDIR,   // 下一步是进入子目录
NFA_IS_ENTRY_PARENT,   // 下一步是返回上级目录
NFA_IS_TERMINATE_CURR, // 终止本次搜索
NFA_IS_EXIT_SEARCH,    // 下一步是终止所有搜索
NFA_IS_UNDEFINED,      // 未定义,什么也不做
}NEXT_FIND_ACTION_E;


好了,还有一些其他的代码,以后慢慢贴。

15 个解决方案

#1



/* 搜索某个目录,在搜索完这一层目录后就直接返回了,不主动进入下级目录 */
static NEXT_FIND_ACTION_E ts_search_in_node(FOLDER_NODE_T *rootp, FOLDER_NODE_T **retnode)
{
FOLDER_NODE_T *new_node = NULL;
FOLDER_NODE_T *old_node = NULL;
FINDDATA_T      finddata = {0};
FINDDATA_HANDLE fileHandle = INVALID_HANDLE; 
NEXT_FIND_ACTION_E next_do = NFA_IS_ENTRY_PARENT;
char *tobefind = NULL;
int  cwlength = 0;
char cwpath[MAX_PATH+4]={0}; // "cd path"

if(TS_GETCWD(cwpath, MAX_PATH))
{
MSG_SHOW("ts_search_in_node at: %s.\n",cwpath);
}
else
{
MSG_SHOW("ts_search_in_node get current work directory failed!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

// 先赋值,让返回去的node为空,以便后面程序的判断
*retnode = NULL;

// 是否需要chdir这个函数来修改工作时的路径呢
if(rootp == NULL)
{
MSG_SHOW("Passed a NULL pointer (rootp)! Terminate current search!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

if(retnode == NULL)
{
MSG_SHOW("Passed a NULL pointer (retnode)! Terminate current search!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

cwlength = TS_STRLEN(cwpath);

// tobefind --> D:\testfolder\*.*
#if defined(MEM_LEAK_CHECK)
tobefind = (char*)ts_alloc_with_mem_check(cwlength+1+4);
#else
tobefind = (char*)TS_MALLOC(cwlength+1+4);
#endif
if(tobefind == NULL)
{
MSG_SHOW("Can not allocate memory for variable!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

TS_MEMSET(tobefind, 0, cwlength+1+4);
TS_STRCPY(tobefind, cwpath);
TS_STRCPY(tobefind+cwlength, "\\*.*");

MSG_SHOW("find in [%s]\n", tobefind);
fileHandle = _findfirst(tobefind, &finddata);
new_node = old_node = NULL;

if(fileHandle == INVALID_HANDLE)
{
MSG_SHOW("Find first return invalid handle!\n");
next_do = NFA_IS_TERMINATE_CURR;
}
else
{
do
{
if ((finddata.attrib & _A_SUBDIR) && (finddata.name[0] != '.'))
{
//DBG_PRINT("Find a folder \"%s\".\n", finddata.name);
RECORD_TO(FOLDER_LIST, "%s\\%s\n", cwpath, finddata.name);
new_node = ts_alloc_node(finddata.name, TS_STRLEN(finddata.name));
if (new_node == NULL)
{
MSG_SHOW("Find a folder but can not allocate memory!\n");
next_do = NFA_IS_EXIT_SEARCH;
break;
}
else if (old_node == NULL)
{
// 认为是第一个孩子,
rootp->first_child_ptr = new_node;
new_node->parent_ptr = rootp;

else
{
old_node->next_brother_ptr = new_node;
new_node->prev_brother_ptr = old_node;
}

old_node = new_node;
// 有找到文件夹,则需要继续深入,不返回上一级目录
// 准备进入最后一个找到的文件夹
next_do = NFA_IS_ENTRY_SUBDIR;
*retnode = new_node;
searched_folder_total ++;
}
else if ((finddata.attrib & _A_SUBDIR) && (finddata.name[0] == '.'))
{
/* "." 和 ".." 而且 ".svn" 这样的特殊文件夹也会被忽略 */
}
else
{
//DBG_PRINT("Find a file \"%s\".\n", finddata.name);
RECORD_TO(FILE_LIST, "%s\\%s\n", cwpath, finddata.name);
/* do something you want to ... */
searched_file_total ++;
}
}while(_findnext(fileHandle, &finddata) != INVALID_HANDLE);

//关闭当前正在查找的文件夹的句柄
_findclose(fileHandle);
}

exit_tag:
if(tobefind != NULL)
{
#if defined(MEM_LEAK_CHECK)
ts_free_with_mem_check((void*)tobefind);
#else
TS_FREE(tobefind);
#endif
tobefind = NULL;
}
return next_do;
}

#2



/* 启动搜索 */
static PROG_RET_VAL_E ts_do_search(FOLDER_NODE_T **rootp)
{
int  loop_next            = TRUE;
int  find_upper           = TRUE;
int  cwpath_ret_level     = 0;
int  cwlength             = 0;
int  func_ret_val         = 0;
char cwpath[MAX_PATH]     = {0}; // "cd path"
FOLDER_NODE_T *sub_root   = *rootp;
FOLDER_NODE_T *ret_root   = NULL;
FOLDER_NODE_T *to_be_del  = NULL;
PROG_RET_VAL_E ret_val    = PROG_RET_SUCESSFUL;
NEXT_FIND_ACTION_E action = NFA_IS_ENTRY_SUBDIR;


//切换工作路径,后面就利用系统的cd命令根据action来决定是进入还是退出
if(rootp == NULL || *rootp == NULL)
{
MSG_SHOW("Parameter passed to ts_do_search is NULL!\n");
ret_val = PROG_RET_ILLEGAL_PARA;
goto exit_func;
}

if (sub_root->name_leng > 3 
&& sub_root->name_ptr[1] == ':' 
&& (sub_root->name_ptr[2] == '\\' || sub_root->name_ptr[2] == '/'))
{
func_ret_val = TS_CHDIR(sub_root->name_ptr);
if(func_ret_val != 0)
{
MSG_SHOW("Change directory filed or directory is not exist! func_ret_val=%d.\n",func_ret_val);
ret_val = PROG_RET_PATH_NOT_EXIST;
goto exit_func;
}
}

if(TS_GETCWD(cwpath, MAX_PATH))
{
MSG_SHOW("ts_do_search at: %s.\n",cwpath);
}
else
{
MSG_SHOW("ts_do_search get current work directory failed!\n");
ret_val = PROG_RET_GET_WD_FAIL;
goto exit_func;
}

// 移除路径末尾的路径分隔符
if(cwpath[cwlength - 1] == '\\' || cwpath[cwlength - 1] == '/')
{
cwpath[cwlength - 1] = '\0';
cwlength -= 1;
}

if(FILE_LIST == NULL)
{
MSG_SHOW("Create searched_file.lst at %s.\n",cwpath);
FILE_LIST = fopen("searched_file.lst", "wb");
}
if(FOLDER_LIST == NULL)
{
MSG_SHOW("Create searched_folder.lst at %s.\n",cwpath);
FOLDER_LIST = fopen("searched_folder.lst", "wb");
}

do 
{
to_be_del = sub_root;
action = ts_search_in_node(sub_root, &ret_root);
switch(action)
{
case NFA_IS_ENTRY_SUBDIR:
DBG_PRINT("==>NFA_IS_ENTRY_SUBDIR\n");
if(ret_root != NULL)
{
sub_root = ret_root;
//要修正下路径,否则查找会失败的
ts_path_combine(cwpath, TS_STRLEN(cwpath), sub_root->name_ptr, sub_root->name_leng, MAX_PATH);
TS_CHDIR(cwpath);
ret_root = NULL;
}
else
{
MSG_SHOW("There must be some error!\n");
loop_next = FALSE;
}
break;

case NFA_IS_ENTRY_PARENT:
DBG_PRINT("==>NFA_IS_ENTRY_PARENT\n");
cwpath_ret_level = 0;
do
{
find_upper = FALSE;
cwpath_ret_level += 1;
if(sub_root == NULL)
{
loop_next = FALSE;
}
else if (sub_root->prev_brother_ptr != NULL)
{
to_be_del = sub_root;
sub_root = sub_root->prev_brother_ptr;
}
else
{
if(sub_root->parent_ptr != NULL)
{
DBG_PRINT("find_upper: sub_root->parent = %s.\n", sub_root->parent_ptr->name_ptr);
}
to_be_del = sub_root;
sub_root = sub_root->parent_ptr;
find_upper = TRUE;
}
}while(find_upper);

/* 如果到了*节点,注意删除后将指针设置成空 */
if(to_be_del == *rootp)
{
ts_delete_node(&to_be_del);
//注意将指针设置成NULL
*rootp = NULL;
}
else
{
ts_delete_node(&to_be_del);
}

if(loop_next)
{
//要修正下路径,否则查找会失败的
ts_path_back(cwpath, TS_STRLEN(cwpath), cwpath_ret_level);
ts_path_combine(cwpath, TS_STRLEN(cwpath), sub_root->name_ptr, sub_root->name_leng, MAX_PATH);
TS_CHDIR(cwpath);
}
break;

case NFA_IS_TERMINATE_CURR:
// 这个case下面的还没调试过,暂时采用NFA_IS_ENTRY_PARENT同样的处理
DBG_PRINT("==>NFA_IS_TERMINATE_CURR\n");
cwpath_ret_level = 0;
do
{
find_upper = FALSE;
cwpath_ret_level += 1;
if(sub_root == NULL)
{
loop_next = FALSE;
}
else if (sub_root->prev_brother_ptr != NULL)
{
to_be_del = sub_root;
sub_root = sub_root->prev_brother_ptr;
}
else
{
if(sub_root->parent_ptr != NULL)
{
DBG_PRINT("find_upper: sub_root->parent = %s.\n", sub_root->parent_ptr->name_ptr);
}
to_be_del = sub_root;
sub_root = sub_root->parent_ptr;
find_upper = TRUE;
}
}while(find_upper);

/* 如果到了*节点,注意删除后将指针设置成空 */
if(to_be_del == *rootp)
{
ts_delete_node(&to_be_del);
//注意将指针设置成NULL
*rootp = NULL;
}
else
{
ts_delete_node(&to_be_del);
}

if(loop_next)
{
//要修正下路径,否则查找会失败的
ts_path_back(cwpath, TS_STRLEN(cwpath), cwpath_ret_level);
ts_path_combine(cwpath, TS_STRLEN(cwpath), sub_root->name_ptr, sub_root->name_leng, MAX_PATH);
TS_CHDIR(cwpath);
}
break;

case NFA_IS_EXIT_SEARCH:
MSG_SHOW("The last search returned NFA_IS_EXIT_SEARCH, stop all search!\n");
ts_delete_node(rootp);
//注意将指针设置成NULL
to_be_del = NULL;
*rootp = NULL;
ret_val = PROG_RET_PROG_TERMINATE;
loop_next = FALSE;
break;

default:
MSG_SHOW("The last search returned a unknown error, stop all search!\n");
ts_delete_node(rootp);
//注意将指针设置成NULL
to_be_del = NULL;
*rootp = NULL;
ret_val = PROG_RET_UNKNOWN_ERR;
loop_next = FALSE;
break;
}

} while (loop_next);

exit_func:
return ret_val;
}

#3


其中,为了检测内存泄露,特地使用一个函数,改装内存的申请与释放过程,代码如下:

#if defined(MEM_LEAK_CHECK)
static long int memoryUsedMax = 0;
static long int memoryUsedCur = 0;
static MEM_LEAK_T *memLeakListPtr = NULL;
static void* ts_alloc_with_mem_check(size_t memsize)
{
void *allocated_mem_ptr = NULL;
register MEM_LEAK_T *newnode = NULL;
register MEM_LEAK_T *prevnode = NULL;
register MEM_LEAK_T *currnode = memLeakListPtr;

allocated_mem_ptr = (void*)TS_MALLOC(memsize);

if(allocated_mem_ptr != NULL)
{
newnode = (MEM_LEAK_T*)TS_MALLOC(sizeof(MEM_LEAK_T));
if(newnode != NULL)
{
/* 申请一个新的节点,记录内存申请信息,插入链表 */
newnode->memAdr = (int)allocated_mem_ptr;
newnode->memSize = memsize;
newnode->next = NULL;

while(currnode != NULL)
{
prevnode = currnode;
currnode = currnode->next;
}

if(prevnode == NULL)
{
memLeakListPtr = newnode;
}
else
{
prevnode->next = newnode;
}

memoryUsedCur += (memsize + sizeof(MEM_LEAK_T));
if(memoryUsedMax<memoryUsedCur)
{
memoryUsedMax = memoryUsedCur;
}
}
}
else
{
MEM_PRINT("ts_alloc_with_mem_check FAILED!\n");
}

return allocated_mem_ptr;
}

static void ts_free_with_mem_check(void* memPtr)
{
register MEM_LEAK_T *currnode = memLeakListPtr;
register MEM_LEAK_T *prevnode = NULL;

while(currnode != NULL)
{
if(currnode->memAdr == (int)memPtr)
{
break;
}
else
{
prevnode = currnode;
currnode = currnode->next;
}
}

TS_FREE(memPtr);
if(currnode != NULL)
{
memoryUsedCur -= (currnode->memSize + sizeof(MEM_LEAK_T));
if(prevnode != NULL)
{
prevnode->next = currnode->next;
currnode->next = NULL;
TS_FREE(currnode);
currnode = NULL;
}
else
{
/* the head of list */
if(currnode->next == NULL)
{
TS_FREE(currnode);
currnode = NULL;
memLeakListPtr = NULL;
}
else
{
memLeakListPtr = currnode->next;
currnode->next = NULL;
TS_FREE(currnode);
currnode = NULL;
}
}
}

}

static void ts_mem_check_at_prog_exit(void)
{
int no_memory_leak_flag = TRUE;
register MEM_LEAK_T *currnode = memLeakListPtr;
register MEM_LEAK_T *prevnode = NULL;

while(currnode != NULL)
{
MEM_PRINT("\nmemory leaked at 0x%08x, size is %4d bytes.", currnode->memAdr, currnode->memSize);
prevnode = currnode;
currnode = currnode->next;
TS_FREE((void*)(prevnode->memAdr));
TS_FREE(prevnode);
no_memory_leak_flag = FALSE;
}

if(no_memory_leak_flag)
{
MEM_PRINT("There is no memory leak. memoryUsedCur=%d.\n",memoryUsedCur);
MSG_SHOW("memoryUsedMax=%d.\n",memoryUsedMax);
}
}

#endif /*defined(MEM_LEAK_CHECK)*/

#4


不错 如果是我我会选择用树来实现

#5


引用 4 楼  的回复:
不错 如果是我我会选择用树来实现

请问,如果用树来实现的话,其基本思路是怎样的呢?
我没学过数据结构,很多东西都不太理解。希望你能稍微做点提醒,得空我再研究下树的实现。

#6


引用 4 楼  的回复:
不错 如果是我我会选择用树来实现

刚才去百度了下,你说的树,指的是二叉树吧?深度优先搜索和广度优先搜索,是不?这两个算法的概念我看了下,但是没有确切的实践,始终没法理解透彻,也没法实际应用。不知道你能否开个贴,示意部分代码,参考学习下呢?

#7


[liangdong@bb-browser-test00.vm.baidu.com c_project]$ make
gcc -g -I. -I../libs/include   -c -o main.o main.c
gcc -o main main.o 
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ ./main 
/home/liangdong/c_project/main.c


楼主辛苦了。

#8


NAME
       glob, globfree - find pathnames matching a pattern, free memory from glob()

SYNOPSIS
       #include <glob.h>

       int glob(const char *pattern, int flags,
                int errfunc(const char *epath, int eerrno),
                glob_t *pglob);
       void globfree(glob_t *pglob);


NAME
       realpath - return the canonicalized absolute pathname

SYNOPSIS
       #include <limits.h>
       #include <stdlib.h>

       char *realpath(const char *path, char *resolved_path);

#9


引用 7 楼  的回复:
C/C++ code
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ make
gcc -g -I. -I../libs/include   -c -o main.o main.c
gcc -o main main.o 
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ ./m……
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ cat main.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int main(int argc, char* const argv[]) {
        char path[PATH_MAX];
        if (realpath("./main.c", path) != NULL) {
                printf("%s\n", path);
        }
        return 0;
}


忘了贴代码。

#10


引用 9 楼  的回复:
引用 7 楼 的回复:

C/C++ code
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ make
gcc -g -I. -I../libs/include -c -o main.o main.c
gcc -o main main.o
[liangdong@bb-browser-test00.vm.baidu.com c……

你用代码描述了这么多,好像,没有说明什么,我去百度了一下,你调用的这个函数好像是用来获取文件的绝对路径的。
realpath()用来将参数path所指的相对路径转换成绝对路径后存于参数resolved_path所指的字符串数组或指针中   返回值: 成功则返回指向resolved_path的指针,失败返回NULL,错误代码存于errno 

这似乎跟遍历文件夹的联系不大啊。

#11


还是觉得递归比较好用。

#12


system("dir /b /s /a-d c:\\*.* >d:\\allfiles.txt");
//读文件d:\\allfiles.txt的内容即C:\\下所有文件的绝对路径
请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接文件、稀疏文件……等各种意料之外的情况时,API会处理的不全面或陷入死循环,而shell命令不会。

#13


引用 12 楼  的回复:
system("dir /b /s /a-d c:\\*.* >d:\\allfiles.txt");
//读文件d:\\allfiles.txt的内容即C:\\下所有文件的绝对路径
请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接……

大佬,又看到你来顶我的帖子了。我记得我以前提这个问题的时候你就是这么指导的。你说的很对。
我在编写这个程序的时候还在担心如果碰到unicode字符的文件名的时候,我的strlen, strcpy还有效么?
庆幸的是,我在VC6下测试,暂时没发现什么异常。想来是VC6里面的库支持unicode吧。
通过这个实践,我对之前学习C语言的链表的内容有了很大程度掌握。这个才是关键!
谢谢你的指导!

#14


引用 11 楼  的回复:
还是觉得递归比较好用。

试想如果你的文件夹深度在8纪以上,文件夹数量上万,文件的数量也上万,此时,来用用你的递归,是否存在局限呢?

#15


楼主,威武,代码………………

#1



/* 搜索某个目录,在搜索完这一层目录后就直接返回了,不主动进入下级目录 */
static NEXT_FIND_ACTION_E ts_search_in_node(FOLDER_NODE_T *rootp, FOLDER_NODE_T **retnode)
{
FOLDER_NODE_T *new_node = NULL;
FOLDER_NODE_T *old_node = NULL;
FINDDATA_T      finddata = {0};
FINDDATA_HANDLE fileHandle = INVALID_HANDLE; 
NEXT_FIND_ACTION_E next_do = NFA_IS_ENTRY_PARENT;
char *tobefind = NULL;
int  cwlength = 0;
char cwpath[MAX_PATH+4]={0}; // "cd path"

if(TS_GETCWD(cwpath, MAX_PATH))
{
MSG_SHOW("ts_search_in_node at: %s.\n",cwpath);
}
else
{
MSG_SHOW("ts_search_in_node get current work directory failed!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

// 先赋值,让返回去的node为空,以便后面程序的判断
*retnode = NULL;

// 是否需要chdir这个函数来修改工作时的路径呢
if(rootp == NULL)
{
MSG_SHOW("Passed a NULL pointer (rootp)! Terminate current search!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

if(retnode == NULL)
{
MSG_SHOW("Passed a NULL pointer (retnode)! Terminate current search!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

cwlength = TS_STRLEN(cwpath);

// tobefind --> D:\testfolder\*.*
#if defined(MEM_LEAK_CHECK)
tobefind = (char*)ts_alloc_with_mem_check(cwlength+1+4);
#else
tobefind = (char*)TS_MALLOC(cwlength+1+4);
#endif
if(tobefind == NULL)
{
MSG_SHOW("Can not allocate memory for variable!\n");
next_do = NFA_IS_TERMINATE_CURR;
goto exit_tag;
}

TS_MEMSET(tobefind, 0, cwlength+1+4);
TS_STRCPY(tobefind, cwpath);
TS_STRCPY(tobefind+cwlength, "\\*.*");

MSG_SHOW("find in [%s]\n", tobefind);
fileHandle = _findfirst(tobefind, &finddata);
new_node = old_node = NULL;

if(fileHandle == INVALID_HANDLE)
{
MSG_SHOW("Find first return invalid handle!\n");
next_do = NFA_IS_TERMINATE_CURR;
}
else
{
do
{
if ((finddata.attrib & _A_SUBDIR) && (finddata.name[0] != '.'))
{
//DBG_PRINT("Find a folder \"%s\".\n", finddata.name);
RECORD_TO(FOLDER_LIST, "%s\\%s\n", cwpath, finddata.name);
new_node = ts_alloc_node(finddata.name, TS_STRLEN(finddata.name));
if (new_node == NULL)
{
MSG_SHOW("Find a folder but can not allocate memory!\n");
next_do = NFA_IS_EXIT_SEARCH;
break;
}
else if (old_node == NULL)
{
// 认为是第一个孩子,
rootp->first_child_ptr = new_node;
new_node->parent_ptr = rootp;

else
{
old_node->next_brother_ptr = new_node;
new_node->prev_brother_ptr = old_node;
}

old_node = new_node;
// 有找到文件夹,则需要继续深入,不返回上一级目录
// 准备进入最后一个找到的文件夹
next_do = NFA_IS_ENTRY_SUBDIR;
*retnode = new_node;
searched_folder_total ++;
}
else if ((finddata.attrib & _A_SUBDIR) && (finddata.name[0] == '.'))
{
/* "." 和 ".." 而且 ".svn" 这样的特殊文件夹也会被忽略 */
}
else
{
//DBG_PRINT("Find a file \"%s\".\n", finddata.name);
RECORD_TO(FILE_LIST, "%s\\%s\n", cwpath, finddata.name);
/* do something you want to ... */
searched_file_total ++;
}
}while(_findnext(fileHandle, &finddata) != INVALID_HANDLE);

//关闭当前正在查找的文件夹的句柄
_findclose(fileHandle);
}

exit_tag:
if(tobefind != NULL)
{
#if defined(MEM_LEAK_CHECK)
ts_free_with_mem_check((void*)tobefind);
#else
TS_FREE(tobefind);
#endif
tobefind = NULL;
}
return next_do;
}

#2



/* 启动搜索 */
static PROG_RET_VAL_E ts_do_search(FOLDER_NODE_T **rootp)
{
int  loop_next            = TRUE;
int  find_upper           = TRUE;
int  cwpath_ret_level     = 0;
int  cwlength             = 0;
int  func_ret_val         = 0;
char cwpath[MAX_PATH]     = {0}; // "cd path"
FOLDER_NODE_T *sub_root   = *rootp;
FOLDER_NODE_T *ret_root   = NULL;
FOLDER_NODE_T *to_be_del  = NULL;
PROG_RET_VAL_E ret_val    = PROG_RET_SUCESSFUL;
NEXT_FIND_ACTION_E action = NFA_IS_ENTRY_SUBDIR;


//切换工作路径,后面就利用系统的cd命令根据action来决定是进入还是退出
if(rootp == NULL || *rootp == NULL)
{
MSG_SHOW("Parameter passed to ts_do_search is NULL!\n");
ret_val = PROG_RET_ILLEGAL_PARA;
goto exit_func;
}

if (sub_root->name_leng > 3 
&& sub_root->name_ptr[1] == ':' 
&& (sub_root->name_ptr[2] == '\\' || sub_root->name_ptr[2] == '/'))
{
func_ret_val = TS_CHDIR(sub_root->name_ptr);
if(func_ret_val != 0)
{
MSG_SHOW("Change directory filed or directory is not exist! func_ret_val=%d.\n",func_ret_val);
ret_val = PROG_RET_PATH_NOT_EXIST;
goto exit_func;
}
}

if(TS_GETCWD(cwpath, MAX_PATH))
{
MSG_SHOW("ts_do_search at: %s.\n",cwpath);
}
else
{
MSG_SHOW("ts_do_search get current work directory failed!\n");
ret_val = PROG_RET_GET_WD_FAIL;
goto exit_func;
}

// 移除路径末尾的路径分隔符
if(cwpath[cwlength - 1] == '\\' || cwpath[cwlength - 1] == '/')
{
cwpath[cwlength - 1] = '\0';
cwlength -= 1;
}

if(FILE_LIST == NULL)
{
MSG_SHOW("Create searched_file.lst at %s.\n",cwpath);
FILE_LIST = fopen("searched_file.lst", "wb");
}
if(FOLDER_LIST == NULL)
{
MSG_SHOW("Create searched_folder.lst at %s.\n",cwpath);
FOLDER_LIST = fopen("searched_folder.lst", "wb");
}

do 
{
to_be_del = sub_root;
action = ts_search_in_node(sub_root, &ret_root);
switch(action)
{
case NFA_IS_ENTRY_SUBDIR:
DBG_PRINT("==>NFA_IS_ENTRY_SUBDIR\n");
if(ret_root != NULL)
{
sub_root = ret_root;
//要修正下路径,否则查找会失败的
ts_path_combine(cwpath, TS_STRLEN(cwpath), sub_root->name_ptr, sub_root->name_leng, MAX_PATH);
TS_CHDIR(cwpath);
ret_root = NULL;
}
else
{
MSG_SHOW("There must be some error!\n");
loop_next = FALSE;
}
break;

case NFA_IS_ENTRY_PARENT:
DBG_PRINT("==>NFA_IS_ENTRY_PARENT\n");
cwpath_ret_level = 0;
do
{
find_upper = FALSE;
cwpath_ret_level += 1;
if(sub_root == NULL)
{
loop_next = FALSE;
}
else if (sub_root->prev_brother_ptr != NULL)
{
to_be_del = sub_root;
sub_root = sub_root->prev_brother_ptr;
}
else
{
if(sub_root->parent_ptr != NULL)
{
DBG_PRINT("find_upper: sub_root->parent = %s.\n", sub_root->parent_ptr->name_ptr);
}
to_be_del = sub_root;
sub_root = sub_root->parent_ptr;
find_upper = TRUE;
}
}while(find_upper);

/* 如果到了*节点,注意删除后将指针设置成空 */
if(to_be_del == *rootp)
{
ts_delete_node(&to_be_del);
//注意将指针设置成NULL
*rootp = NULL;
}
else
{
ts_delete_node(&to_be_del);
}

if(loop_next)
{
//要修正下路径,否则查找会失败的
ts_path_back(cwpath, TS_STRLEN(cwpath), cwpath_ret_level);
ts_path_combine(cwpath, TS_STRLEN(cwpath), sub_root->name_ptr, sub_root->name_leng, MAX_PATH);
TS_CHDIR(cwpath);
}
break;

case NFA_IS_TERMINATE_CURR:
// 这个case下面的还没调试过,暂时采用NFA_IS_ENTRY_PARENT同样的处理
DBG_PRINT("==>NFA_IS_TERMINATE_CURR\n");
cwpath_ret_level = 0;
do
{
find_upper = FALSE;
cwpath_ret_level += 1;
if(sub_root == NULL)
{
loop_next = FALSE;
}
else if (sub_root->prev_brother_ptr != NULL)
{
to_be_del = sub_root;
sub_root = sub_root->prev_brother_ptr;
}
else
{
if(sub_root->parent_ptr != NULL)
{
DBG_PRINT("find_upper: sub_root->parent = %s.\n", sub_root->parent_ptr->name_ptr);
}
to_be_del = sub_root;
sub_root = sub_root->parent_ptr;
find_upper = TRUE;
}
}while(find_upper);

/* 如果到了*节点,注意删除后将指针设置成空 */
if(to_be_del == *rootp)
{
ts_delete_node(&to_be_del);
//注意将指针设置成NULL
*rootp = NULL;
}
else
{
ts_delete_node(&to_be_del);
}

if(loop_next)
{
//要修正下路径,否则查找会失败的
ts_path_back(cwpath, TS_STRLEN(cwpath), cwpath_ret_level);
ts_path_combine(cwpath, TS_STRLEN(cwpath), sub_root->name_ptr, sub_root->name_leng, MAX_PATH);
TS_CHDIR(cwpath);
}
break;

case NFA_IS_EXIT_SEARCH:
MSG_SHOW("The last search returned NFA_IS_EXIT_SEARCH, stop all search!\n");
ts_delete_node(rootp);
//注意将指针设置成NULL
to_be_del = NULL;
*rootp = NULL;
ret_val = PROG_RET_PROG_TERMINATE;
loop_next = FALSE;
break;

default:
MSG_SHOW("The last search returned a unknown error, stop all search!\n");
ts_delete_node(rootp);
//注意将指针设置成NULL
to_be_del = NULL;
*rootp = NULL;
ret_val = PROG_RET_UNKNOWN_ERR;
loop_next = FALSE;
break;
}

} while (loop_next);

exit_func:
return ret_val;
}

#3


其中,为了检测内存泄露,特地使用一个函数,改装内存的申请与释放过程,代码如下:

#if defined(MEM_LEAK_CHECK)
static long int memoryUsedMax = 0;
static long int memoryUsedCur = 0;
static MEM_LEAK_T *memLeakListPtr = NULL;
static void* ts_alloc_with_mem_check(size_t memsize)
{
void *allocated_mem_ptr = NULL;
register MEM_LEAK_T *newnode = NULL;
register MEM_LEAK_T *prevnode = NULL;
register MEM_LEAK_T *currnode = memLeakListPtr;

allocated_mem_ptr = (void*)TS_MALLOC(memsize);

if(allocated_mem_ptr != NULL)
{
newnode = (MEM_LEAK_T*)TS_MALLOC(sizeof(MEM_LEAK_T));
if(newnode != NULL)
{
/* 申请一个新的节点,记录内存申请信息,插入链表 */
newnode->memAdr = (int)allocated_mem_ptr;
newnode->memSize = memsize;
newnode->next = NULL;

while(currnode != NULL)
{
prevnode = currnode;
currnode = currnode->next;
}

if(prevnode == NULL)
{
memLeakListPtr = newnode;
}
else
{
prevnode->next = newnode;
}

memoryUsedCur += (memsize + sizeof(MEM_LEAK_T));
if(memoryUsedMax<memoryUsedCur)
{
memoryUsedMax = memoryUsedCur;
}
}
}
else
{
MEM_PRINT("ts_alloc_with_mem_check FAILED!\n");
}

return allocated_mem_ptr;
}

static void ts_free_with_mem_check(void* memPtr)
{
register MEM_LEAK_T *currnode = memLeakListPtr;
register MEM_LEAK_T *prevnode = NULL;

while(currnode != NULL)
{
if(currnode->memAdr == (int)memPtr)
{
break;
}
else
{
prevnode = currnode;
currnode = currnode->next;
}
}

TS_FREE(memPtr);
if(currnode != NULL)
{
memoryUsedCur -= (currnode->memSize + sizeof(MEM_LEAK_T));
if(prevnode != NULL)
{
prevnode->next = currnode->next;
currnode->next = NULL;
TS_FREE(currnode);
currnode = NULL;
}
else
{
/* the head of list */
if(currnode->next == NULL)
{
TS_FREE(currnode);
currnode = NULL;
memLeakListPtr = NULL;
}
else
{
memLeakListPtr = currnode->next;
currnode->next = NULL;
TS_FREE(currnode);
currnode = NULL;
}
}
}

}

static void ts_mem_check_at_prog_exit(void)
{
int no_memory_leak_flag = TRUE;
register MEM_LEAK_T *currnode = memLeakListPtr;
register MEM_LEAK_T *prevnode = NULL;

while(currnode != NULL)
{
MEM_PRINT("\nmemory leaked at 0x%08x, size is %4d bytes.", currnode->memAdr, currnode->memSize);
prevnode = currnode;
currnode = currnode->next;
TS_FREE((void*)(prevnode->memAdr));
TS_FREE(prevnode);
no_memory_leak_flag = FALSE;
}

if(no_memory_leak_flag)
{
MEM_PRINT("There is no memory leak. memoryUsedCur=%d.\n",memoryUsedCur);
MSG_SHOW("memoryUsedMax=%d.\n",memoryUsedMax);
}
}

#endif /*defined(MEM_LEAK_CHECK)*/

#4


不错 如果是我我会选择用树来实现

#5


引用 4 楼  的回复:
不错 如果是我我会选择用树来实现

请问,如果用树来实现的话,其基本思路是怎样的呢?
我没学过数据结构,很多东西都不太理解。希望你能稍微做点提醒,得空我再研究下树的实现。

#6


引用 4 楼  的回复:
不错 如果是我我会选择用树来实现

刚才去百度了下,你说的树,指的是二叉树吧?深度优先搜索和广度优先搜索,是不?这两个算法的概念我看了下,但是没有确切的实践,始终没法理解透彻,也没法实际应用。不知道你能否开个贴,示意部分代码,参考学习下呢?

#7


[liangdong@bb-browser-test00.vm.baidu.com c_project]$ make
gcc -g -I. -I../libs/include   -c -o main.o main.c
gcc -o main main.o 
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ ./main 
/home/liangdong/c_project/main.c


楼主辛苦了。

#8


NAME
       glob, globfree - find pathnames matching a pattern, free memory from glob()

SYNOPSIS
       #include <glob.h>

       int glob(const char *pattern, int flags,
                int errfunc(const char *epath, int eerrno),
                glob_t *pglob);
       void globfree(glob_t *pglob);


NAME
       realpath - return the canonicalized absolute pathname

SYNOPSIS
       #include <limits.h>
       #include <stdlib.h>

       char *realpath(const char *path, char *resolved_path);

#9


引用 7 楼  的回复:
C/C++ code
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ make
gcc -g -I. -I../libs/include   -c -o main.o main.c
gcc -o main main.o 
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ ./m……
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ cat main.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int main(int argc, char* const argv[]) {
        char path[PATH_MAX];
        if (realpath("./main.c", path) != NULL) {
                printf("%s\n", path);
        }
        return 0;
}


忘了贴代码。

#10


引用 9 楼  的回复:
引用 7 楼 的回复:

C/C++ code
[liangdong@bb-browser-test00.vm.baidu.com c_project]$ make
gcc -g -I. -I../libs/include -c -o main.o main.c
gcc -o main main.o
[liangdong@bb-browser-test00.vm.baidu.com c……

你用代码描述了这么多,好像,没有说明什么,我去百度了一下,你调用的这个函数好像是用来获取文件的绝对路径的。
realpath()用来将参数path所指的相对路径转换成绝对路径后存于参数resolved_path所指的字符串数组或指针中   返回值: 成功则返回指向resolved_path的指针,失败返回NULL,错误代码存于errno 

这似乎跟遍历文件夹的联系不大啊。

#11


还是觉得递归比较好用。

#12


system("dir /b /s /a-d c:\\*.* >d:\\allfiles.txt");
//读文件d:\\allfiles.txt的内容即C:\\下所有文件的绝对路径
请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接文件、稀疏文件……等各种意料之外的情况时,API会处理的不全面或陷入死循环,而shell命令不会。

#13


引用 12 楼  的回复:
system("dir /b /s /a-d c:\\*.* >d:\\allfiles.txt");
//读文件d:\\allfiles.txt的内容即C:\\下所有文件的绝对路径
请记住,能用shell命令获取文件、文件夹信息或者操作文件、文件夹最好用shell命令获取或者操作,而不要用各种API获取或者操作,因为当遇到非法文件夹名或非法文件名或非法文件长度、非法文件日期、压缩文件、链接……

大佬,又看到你来顶我的帖子了。我记得我以前提这个问题的时候你就是这么指导的。你说的很对。
我在编写这个程序的时候还在担心如果碰到unicode字符的文件名的时候,我的strlen, strcpy还有效么?
庆幸的是,我在VC6下测试,暂时没发现什么异常。想来是VC6里面的库支持unicode吧。
通过这个实践,我对之前学习C语言的链表的内容有了很大程度掌握。这个才是关键!
谢谢你的指导!

#14


引用 11 楼  的回复:
还是觉得递归比较好用。

试想如果你的文件夹深度在8纪以上,文件夹数量上万,文件的数量也上万,此时,来用用你的递归,是否存在局限呢?

#15


楼主,威武,代码………………