C/C++:遍历子目录,枚举文件,FindFirstFile + FindNextFile

本文介绍了一个高效的Windows API文件遍历函数doFileEnumeration(),该函数通过封装FindFirstFile()和FindNextFile(),简化了多层子目录的文件枚举过程,提供了一个易于使用的接口,支持递归处理子目录和文件,适用于快速实现文件遍历任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平时写程序时经常会用到的遍历子目录枚举文件的功能,用 Windows API 函数FindFirstFile() 和 FindNextFile() 直接实现起来会相当繁琐,有许多细节需要注意和记忆,要在短时间内写出可以正常工作的、没有BUG的、能够递归遍历多层子目录并枚举其中所有文件的程序代码,不是一件轻松的事情。以下这个 doFileEnumeration() 函数,是我(liigo)在 Windows API 函数FindFirstFile() 和 FindNextFile() 的基础上封装实现的,可以轻松自如的处理遍历子目录枚举文件的任务,使用起来非常简单,具有较高的实用价值。这个函数其实是我之前发布的易语言“辅助调试支持库”(已开源至googlecode)中“枚举文件”“枚举子目录”这两条命令的底层实现函数。

  doFileEnumeration() 函数功能是实现枚举文件和枚举子目录,支持递归处理多层子目录嵌套的情况。它有五个参数:第一个参数lpPath指定欲遍历的路径(文件夹);第二个参数bRecursion指定是否递归处理子目录;第三个参数bEnumFiles指定是枚举文件还是枚举子目录;第四个参数pFunc为用户回调函数,枚举过程中每遇到一个文件或子目录,都会调用它,并传入这个文件或子目录的完整路径;第五个参数pUserData为用户任意指定的数据,它也将被传入用户回调函数。用户回调函数(EnumerateFunc)有两个参数,一个是文件或子目录的完整路径(lpFileOrPath),一个是用户自定义数据(pUserData),它被自动调用,用户需在此函数中编码处理代码。

  这个函数经过我(liigo)的仔细设计,接口很简洁,使用也方便。有意去除了 FindFirstFile(Ex)/FindNextFile 中过滤文件名称或属性的部分功能,也是出于简化接口的考虑,——在用户回调函数中处理这些事情也是很容易的(在易语言中更容易)。在实现的细节上,重点是对子目录和递归的处理。以下是完整的源代码:


#include <windows.h>  

typedef BOOL (WINAPI *EnumerateFunc) (LPCSTR lpFileOrPath, void* pUserData);  

void doFileEnumeration(LPSTR lpPath, BOOL bRecursion, BOOL bEnumFiles, EnumerateFunc pFunc, void* pUserData)  
{  
	
    static BOOL s_bUserBreak = FALSE;  
    try{  
        //-------------------------------------------------------------------------  
        if(s_bUserBreak) return;  
		
        int len = strlen(lpPath);  
        if(lpPath==NULL || len<=0) return;  
		
        //NotifySys(NRS_DO_EVENTS, 0,0);  
		
        char path[MAX_PATH];  
        strcpy(path, lpPath);  
        if(lpPath[len-1] != '\\') strcat(path, "\\");  
        strcat(path, "*");  
		
        WIN32_FIND_DATA fd;  
        HANDLE hFindFile = FindFirstFile(path, &fd);  
        if(hFindFile == INVALID_HANDLE_VALUE)  
        {  
            ::FindClose(hFindFile); return;  
        }  
		
        char tempPath[MAX_PATH]; BOOL bUserReture=TRUE; BOOL bIsDirectory;  
		
        BOOL bFinish = FALSE;  
        while(!bFinish)  
        {  
            strcpy(tempPath, lpPath);  
            if(lpPath[len-1] != '\\') strcat(tempPath, "\\");  
            strcat(tempPath, fd.cFileName);  
			
            bIsDirectory = ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);  
			
            //如果是.或..  
            if( bIsDirectory  
                && (strcmp(fd.cFileName, ".")==0 || strcmp(fd.cFileName, "..")==0))   
            {         
                bFinish = (FindNextFile(hFindFile, &fd) == FALSE);  
                continue;  
            }  
			
            if(pFunc && bEnumFiles!=bIsDirectory)  
            {  
                bUserReture = pFunc(tempPath, pUserData);  
                if(bUserReture==FALSE)  
                {  
                    s_bUserBreak = TRUE; ::FindClose(hFindFile); return;  
                }  
            }  
			
            //NotifySys(NRS_DO_EVENTS, 0,0);  
			
            if(bIsDirectory && bRecursion) //是子目录  
            {  
                doFileEnumeration(tempPath, bRecursion, bEnumFiles, pFunc, pUserData);  
            }  
			
            bFinish = (FindNextFile(hFindFile, &fd) == FALSE);  
        }  
		
        ::FindClose(hFindFile);  
		
        //-------------------------------------------------------------------------  
    }catch(...){ ASSERT(0); return; }  
}  

BOOL WINAPI myEnumerateFunc(LPCSTR lpFileOrPath, void* pUserData)  
{  
    char* pdot;  
    if((pdot = strrchr(lpFileOrPath, '.')) && stricmp(pdot, ".mp3") == 0)  
    {  
        printf("%s\n", lpFileOrPath);  
    }  
    return TRUE;  
}  

int main()  
{  
    doFileEnumeration("C:\\Music", TRUE, TRUE, myEnumerateFunc, NULL);  
    return 0;  
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值