Recurrsivly iterating through directories

This topic is 3110 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Im using the win32 fuctions FindFirstFile and FindNextFile to creating a Tree control that shows all the folders and sub folders in a current directory. But am having real trouble trying to get it to work. Im testing for "." and "..", but FindNextFile keeps returning bad pointers. Im sure this is due to my error. And im just wondering if there is an easier way of doing what i want. That is getting the directory layout, not building the tree control.

Share on other sites
If using C++, you could just use boost::filesystem. If not, mentioning what programming language you are using might help.

Share on other sites
Here's a somewhat simple but I believe complete example of using the FindFile API for you to compare against.

#include <stdio.h>#include <windows.h>void FindAllFiles(const char * searchThisDir_, bool searchSubDirs, void (*UserFileFunc)(const char *, const char *), void (*UserFolderFunc)(const char *, const char *)){	WIN32_FIND_DATAA FindFileData = {0};	HANDLE hFind = INVALID_HANDLE_VALUE;	char searchDir[2048] = {0};	char searchThisDir[2048] = {0};	size_t searchThisDirLen = 0;	// Convert all /'s to \'s	_snprintf(searchThisDir, 2047, "%s\\", searchThisDir_);	searchThisDirLen = strlen(searchThisDir);	for(size_t x = 0; x < searchThisDirLen; ++x)	{		if(searchThisDir[x] == '/')			searchThisDir[x] = '\\';	}	// We always want the path to end with a directory separator	// (but must fix two escaped \'s in a row)	if(searchThisDirLen >= 2 && searchThisDir[searchThisDirLen - 2] == '\\')	{		searchThisDir[searchThisDirLen - 1] = 0;		searchThisDirLen--;	}	// Begin finding files and folders!	_snprintf(searchDir, 2047, "%s*", searchThisDir);	hFind = FindFirstFileA(searchDir, &FindFileData);	if(hFind == INVALID_HANDLE_VALUE)	{		return;	}	do	{		// Ignore the 'current directory' folder		if(strcmp(FindFileData.cFileName, ".") == 0)		{			continue;		}		// Ignore the 'parent directory' folder		if(strcmp(FindFileData.cFileName, "..") == 0)		{			continue;		}		// If we have a folder		if(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)		{			if(UserFolderFunc) UserFolderFunc(searchThisDir, FindFileData.cFileName);			if(searchSubDirs)			{				char searchDir2[2048] = {0};				_snprintf(searchDir2, 2047, "%s%s", searchThisDir, FindFileData.cFileName);				FindAllFiles(searchDir2, true, UserFileFunc, UserFolderFunc);			}			continue;		}		// Otherwise we have a file		if(UserFileFunc) UserFileFunc(searchThisDir, FindFileData.cFileName);	}	while(FindNextFileA(hFind, &FindFileData) != 0);	FindClose(hFind);}void UserFileFunc(const char * path, const char * title){	printf("Path: %s\nTitle: %s\n\n", path, title);}void UserFolderFunc(const char * path, const char * title){	printf("Path: %s\nTitle: %s\n\n", path, title);}int main(int argc, char* argv[]){	char curPath[MAX_PATH + 1] = {0};	GetCurrentDirectoryA(MAX_PATH, curPath);	//strcat(curPath, "\\");	//strcat(curPath, "/");	FindAllFiles(curPath, true, UserFileFunc, UserFolderFunc);	//FindAllFiles(".", true, UserFileFunc, UserFolderFunc);	return 0;}

There are lots of ways to set it up though. I just happened to need function pointers for handling files and folders, but I've made other variations where I just had the function return a vector of files or worked directly with the paths in the function.

Share on other sites
Quote:
 // If we have a folderif(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)

Note to the OP, for all directories (compressed, hidden, system, archived ones, etc) rather than just "plain" ones change the == to your languages equivalent of bitwise and as dwFileAttributes is a bitmask of potentially several attributes.

Share on other sites
Quote:
Quote:
 // If we have a folderif(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)

Note to the OP, for all directories (compressed, hidden, system, archived ones, etc) rather than just "plain" ones change the == to your languages equivalent of bitwise and as dwFileAttributes is a bitmask of potentially several attributes.

Thanks, I'll take that as a bug in my code since I handle everything else as a file if those bits were to be set. [smile]

Share on other sites
Thankyou guys.

That code will help a lot :)

Share on other sites
Quote:
 int main(int argc, char* argv[]){ char curPath[MAX_PATH + 1] = {0}; GetCurrentDirectoryA(MAX_PATH, curPath);

"MAX_PATH should be enough for everyone".

Except when it isn't., and is actually 32k.

Share on other sites
I've used something like this a couple times in the past.

void findFiles(string path, bool traverseSubDirectories){    WIN32_FIND_DATA fileData;                  HANDLE file = INVALID_HANDLE_VALUE;         string tmpPath= path + "\\*";     // find first file in directory    file = FindFirstFile(tmpPath.c_str(), &fileData);     // Couldn't find first file so display an error    if (file == INVALID_HANDLE_VALUE)    {        cout << "Error finding first file" << endl;        return;    }     // Loop through listing all the files    do    {        if (traverseSubDirectories)        {            if (fileData.cFileName[0] != '.')              {                if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)                  {                    string newPath = path + "\\" + fileData.cFileName;                     findFiles(newPath, traverseSubDirectories);                }            }        }                 if (fileData.dwFileAttributes ^ FILE_ATTRIBUTE_DIRECTORY)              cout << path + "\\" + fileData.cFileName << endl;        }    while (FindNextFile(file, &fileData) != 0);}

Share on other sites
I would following the advice of SiCrane - boost::filesystem::recursive_directory_iterator - not only does it do exactly what you are looking for, but it's portable, and standards conforming, so you can use it in std algorithms :

#include <iostream>#include <algorithm>#include <boost/filesystem.hpp>int main(int argc, char** argv){    using namespace boost::filesystem;    recursive_directory_iterator i("C:\\"), end;    std::vector<path> files;    std::copy(i, end, std::ostream_iterator<path>(std::cout, "\n"));}

Share on other sites
Quote:
 Original post by SiCraneIf using C++, you could just use boost::filesystem. If not, mentioning what programming language you are using might help.

QFE:
        namespace fs = boost::filesystem;        void recurseDirectories(const fs::path &path)        {            if (!fs::is_directory(path))            {                std::cout << "file: " << path << "\n";                return;            }            else                std::cout << "dir: " << path << "\n";            for (fs::directory_iterator i(path), end; i != end; ++i)                recurseDirectories(*i);        }        int main()        {            recurseDirectories("C:/WINDOWS");        }

Share on other sites
Quote:
Original post by nullsquared
Quote:
 Original post by SiCraneIf using C++, you could just use boost::filesystem. If not, mentioning what programming language you are using might help.

QFE:
        namespace fs = boost::filesystem;        void recurseDirectories(const fs::path &path)        {            if (!fs::is_directory(path))            {                std::cout << "file: " << path << "\n";                return;            }            else                std::cout << "dir: " << path << "\n";            for (fs::directory_iterator i(path), end; i != end; ++i)                recurseDirectories(*i);        }        int main()        {            recurseDirectories("C:/WINDOWS");        }

What's wrong with boost::filesystem::recursive_directory_iterator?