Sign in to follow this  
maya18222

Recurrsivly iterating through directories

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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:

// If we have a folder
if(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 this post


Link to post
Share on other sites
Quote:
Original post by adeyblue
Quote:

// If we have a folder
if(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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
If 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 this post


Link to post
Share on other sites
Quote:
Original post by nullsquared
Quote:
Original post by SiCrane
If 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?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this