Click here to Skip to main content
Click here to Skip to main content
Go to top

File and Directory Enumeration

, 3 Mar 2003
Rate this:
Please Sign up or sign in to vote.
Template based file and directory enumeration class.
<!-- Add the rest of your HTML here -->

Introduction

Often we need to enumerate files and/or directories and end up writing code like this (pseudocode):

HANDLE hFind = FindFirstFile(...)
while(!lastfile)
{
    // do something if the file is not "." and not ".."
    FindNextFile(...);
}

And since it is so simple we write it again and again. As simple as it seems, it is prone to many errors and we make these errors as often as we write this simple code.

This was the main reason for me to create a template based class to enumerate files and directories. The class does not care about the actual data you need to preserve, or how you represent it. It just cares about correctly recursing a folder and enumerating its content.

The main features of this template class are:

  • thread safety
  • separation of logic from data
  • simple to use

Implementation

The implementation is as follows:

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

The most vital and used functions are the following virtual functions:

virtual bool CheckUseDir(LPCTSTR pstrPath,
    WIN32_FIND_DATA* pwfd);

This function is called for every found folder. If the folder should be used, the function has to return true, returning false will skip this folder. The default implementation returns always true.

virtual bool CheckUseFile(LPCTSTR pstrPath,
    WIN32_FIND_DATA* pwfd);

This function is called for every found file. It gets passed the full find-file information. If the file should be used, the function has to return true, returning false will skip this file. The default implementation returns always true.

You can implement simple filtering by filename (or extension) like this:

bool CheckUseFile(LPCTSTR, WIN32_FIND_DATA* pwfd)
{
  return ::PathMatchSpec(pwfd->cFileName, _T("*.jpg"));
}
virtual bool HandleRawFile(LPCTSTR pstrFile);

This function is called for every file found after CheckUseFile returned true. If the file should be further used, the function has to return true, returning false will skip this file. The default implementation returns always true.

This function is designed to implement a higher level file processing as it is necessary when you process a archive file. If a archive is considered valid during this function call, one might extract it and then loop again over the extracted files. In this case this function would return false.

virtual void HandleFile(T* pFile); // T being the typename

This function is the last to be called to use the file. Normally one would then store the file information in an array or list.

virtual void FinishedDir(LPCTSTR pstrDir);

After a folder is completely processed this function is called. The folder is not more touched after this function call. You can safely delete the folder for example.

Error handling

If errors occur during any stage of the processing, an error handler (HandleError()) is called. The function is provided with location of the error and the error code. The location is one of the locations defined (RDLOC_xxx)in the class header. The error code is the error code returned by GetLastError().

HandleError() has to return one of the error continuation codes defined (RDEH_xxx) in the class header. You can cause the enumeration to continue with the next folder or file, continue normally, abort or fail by returning the appropriate code.

Starting/Stopping

The file and folder enumeration is started by calling Run(...) with a directory as parameter. You may or may not add a backslash to the directory. The function takes care of proper handling in any case.

To stop the enumeration at any time, call CancelRun(). Stopping is implemented through an event object. If you must attach the class to an existing event you can call SetEvent(...) with your own event handle before starting the enumeration.

Samples

The source code contains also two often used variations: class CDirectoryContent and class CCleanDir.

CDirectoryContent delivers an array (std::vector or CArray) of files contained in the directory provided and CCleanDir recursively erases all files in the directory.

The demo project includes a CDirectoryContent derived class which implements a simple wildcard filter.

Compatibility

Written, compiled and tested with VC6 SP5. Unicode safe. Requires Version 4.71 or later of Shlwapi.dll (uses Path...() functions). If used with in a MFC project it will use CString and CArray classes, otherwise it uses std::string and std::vector.

References

Have a look also at some of the other implementations here at CodeProject:

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

No Biography provided

Comments and Discussions

 
Question_vsntprintf needs tchar.h Pinmemberbobbysoon4-Aug-13 21:40 
Generalproblem with samba Pinmemberraphaelverdier23-Jul-09 23:34 
GeneralRe: problem with samba PinmemberAndreas Saurwein Franci Gonçalves24-Jul-09 3:15 
GeneralIt doesn't compile (at least in VS 2005) Pinmemberdruri30-Sep-06 11:55 
GeneralGreat job! Pinmemberuj_mipt3-May-06 7:00 
GeneralDirectory enumerator for fyles beyond 260 bytes. PinmemberSandeep. Vaidya22-Apr-06 5:07 
GeneralRe: Directory enumerator for fyles beyond 260 bytes. Pinmemberdungbkhn17-May-06 4:47 
QuestionSimplified Example? Pinmemberwayvirgo10-Sep-04 17:17 
AnswerRe: Simplified Example? PinsussAnonymous23-Sep-04 11:25 
GeneralRe: Simplified Example? PinmemberSandeep. Vaidya17-May-06 21:27 
GeneralRe: Simplified Example? PinmemberSandeep. Vaidya17-May-06 21:28 
GeneralDoesn't store path PinsussAnonymous1-Oct-03 18:06 
GeneralRe: Doesn't store path PinmemberSaurweinAndreas2-Oct-03 15:50 
GeneralYou need to rename it Pinmemberfigmo7-Aug-03 13:52 
GeneralRe: You need to rename it PinmemberSaurweinAndreas7-Aug-03 14:52 
GeneralRe: You need to rename it Pinmemberfigmo7-Aug-03 15:40 
QuestionThread safe? Pinmember.:fl0yd:.14-Jun-03 13:20 
AnswerRe: Thread safe? Definitely! PinmemberSaurweinAndreas8-Jul-03 6:21 
QuestionIs this really the best way ? Pinmemberyarp4-Mar-03 19:02 
AnswerRe: Is this really the best way ? PinmemberAndreas Saurwein5-Mar-03 4:22 
GeneralRe: Is this really the best way ? Pinmemberyarp5-Mar-03 7:03 
GeneralRe: Is this really the best way ? PinmemberAndreas Saurwein6-Mar-03 5:04 
GeneralRe: Is this really the best way ? Pinmemberyarp6-Mar-03 7:15 
GeneralRe: Is this really the best way ? PinmemberAndreas Saurwein7-Mar-03 0:26 
GeneralRe: Is this really the best way ? Pinmemberyarp7-Mar-03 6:13 
GeneralComments PinmemberChopper4-Mar-03 3:13 
GeneralRe: Comments PinmemberAndreas Saurwein4-Mar-03 3:23 
GeneralRe: Comments Pinmemberdog_spawn4-Mar-03 9:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140905.1 | Last Updated 4 Mar 2003
Article Copyright 2003 by Andreas S. Franci Gonçalves
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid