文件和目录枚举






4.61/5 (12投票s)
基于模板的文件和目录枚举类。
引言
我们经常需要枚举文件和/或目录,并最终编写类似以下的代码(伪代码)
HANDLE hFind = FindFirstFile(...) while(!lastfile) { // do something if the file is not "." and not ".." FindNextFile(...); }
由于它非常简单,所以我们一遍又一遍地编写它。尽管它看起来很简单,但它容易出错,而且我们编写这段简单代码的频率很高,犯错误的频率也同样高。
这是我创建模板类来枚举文件和目录的主要原因。该类不关心您需要保留的实际数据,也不关心您如何表示它。它只关心正确地递归遍历文件夹并枚举其内容。
这个模板类的主要特性是:
- 线程安全
- 逻辑与数据的分离
- 易于使用
实现
实现如下:
for each folder (which is not '.' or '..')
if folder should be used
run the loop again in this folder
for each file
if file should be used
handle the filename
handle the file
finish processing
最重要和最常用的函数是以下虚函数:
virtual bool CheckUseDir(LPCTSTR pstrPath,
WIN32_FIND_DATA* pwfd);
此函数针对每个找到的文件夹调用一次。如果应该使用该文件夹,则函数必须返回true
,返回false
将跳过该文件夹。默认实现始终返回true。
virtual bool CheckUseFile(LPCTSTR pstrPath,
WIN32_FIND_DATA* pwfd);
此函数针对每个找到的文件调用一次。它会收到完整的查找文件信息。如果应该使用该文件,则函数必须返回true
,返回false
将跳过该文件。默认实现始终返回true。
您可以通过以下方式实现简单的按文件名(或扩展名)过滤:
bool CheckUseFile(LPCTSTR, WIN32_FIND_DATA* pwfd) { return ::PathMatchSpec(pwfd->cFileName, _T("*.jpg")); }
virtual bool HandleRawFile(LPCTSTR pstrFile);
此函数在CheckUseFile
返回true
后,针对每个找到的文件调用一次。如果文件应继续使用,则函数必须返回true
,返回false
将跳过该文件。默认实现始终返回true。
此函数设计用于实现更高级的文件处理,因为在处理存档文件时需要它。如果在此函数调用期间认为存档有效,则可能会提取它,然后再次循环遍历提取的文件。在这种情况下,此函数将返回false。
virtual void HandleFile(T* pFile); // T 是类型名
这是使用文件的最后一个调用函数。通常,您会将其文件信息存储在数组或列表中。
virtual void FinishedDir(LPCTSTR pstrDir);
在文件夹完全处理完毕后调用此函数。调用此函数后,该文件夹将不再被访问。您可以安全地删除该文件夹,例如。
错误处理
如果在处理的任何阶段发生错误,将调用错误处理程序(HandleError()
)。该函数会收到错误的发生位置和错误代码。发生位置是类头文件中定义的某个位置(RDLOC_xxx
)。错误代码是GetLastError()
返回的错误代码。
HandleError()
必须返回类头文件中定义的错误继续代码之一(RDEH_xxx
)。通过返回适当的代码,您可以使枚举继续处理下一个文件夹或文件、正常继续、中止或失败。
开始/停止
文件和文件夹枚举通过调用Run(...)
并以目录作为参数来启动。您可以选择在目录末尾添加斜杠,也可以不加。该函数在任何情况下都会正确处理。
要随时停止枚举,请调用CancelRun()
。停止是通过事件对象实现的。如果您必须将类附加到现有事件,可以在开始枚举之前调用SetEvent(...)
并传递您自己的事件句柄。
示例
源代码还包含两个常用的变体:class CDirectoryContent
和class CCleanDir
。
CDirectoryContent
提供一个数组(std::vector
或CArray
)来存储目录中的文件,而CCleanDir
则递归删除目录中的所有文件。
演示项目包含一个派生自CDirectoryContent
的类,该类实现了一个简单的通配符过滤器。
兼容性
使用VC6 SP5编写、编译和测试。Unicode安全。需要Shlwapi.dll 4.71或更高版本(使用Path...()
函数)。如果与MFC项目一起使用,它将使用CString
和CArray
类,否则它将使用std::string
和std::vector
。
参考文献
也可以看看CodeProject上的一些其他实现: