Reputation:
I'm trying to create a program using C and the WIN32 API to iterate though directories trees. Can anybody help modify the code to make it work without the recursive feature?
void WINAPI IterateFiles(char* Directory)
{
HANDLE hFind;
WIN32_FIND_DATA Win32FindData;
char SearchName[MAX_PATH], FullPath[MAX_PATH];
memset(SearchName, 0, sizeof(SearchName));
memset(&Win32FindData, 0, sizeof(WIN32_FIND_DATA));
sprintf(SearchName, "%s\\*", Directory);
hFind = FindFirstFileA(SearchName, &Win32FindData);
if (hFind != INVALID_HANDLE_VALUE)
{
while (FindNextFileA(hFind, &Win32FindData))
{
if (Win32FindData.cFileName[0] == '.')
{
continue;
}
memset(FullPath, 0, sizeof(FullPath));
sprintf(FullPath, "%s\\%s", Directory, Win32FindData.cFileName);
if (Win32FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
MessageBoxA(NULL, FullPath, "Directory", MB_OK);
IterateFiles(FullPath);
}
else
{
MessageBoxA(NULL, FullPath, "File", MB_OK);
}
}
FindClose(hFind);
}
}
Upvotes: 1
Views: 561
Reputation: 3890
There are two specific methods: breadth-first traversal implemented with queues and depth-first traversal implemented with stacks.
I explain in detail how to use queues (similar to using stacks):
- First add the path of this folder to a queue.
- Determine whether the number of elements in the queue is greater than 0. If the number of elements is greater than 0, traverse the folder corresponding to the first element. If there is a folder in this folder, add the path of this folder to the queue. After scanning a folder, the first element is popped out of the queue, and the second step is continued. If there is no element in the queue, the third step is executed.
- Exit the loop.
Here is the sample I implemented in C++:
#include <Windows.h>
#include <iostream>
#include <queue>
using namespace std;
void QueryFileCounts(string Path)
{
queue<std::string> qFolders;
qFolders.push(Path);
WIN32_FIND_DATA findResult;
HANDLE handle = NULL;
while (qFolders.size() > 0)
{
std::string tempFolder = qFolders.front();
tempFolder.append("\\*.*");
handle = FindFirstFile(tempFolder.c_str(), &findResult);
do
{
if (findResult.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (lstrcmp(".", findResult.cFileName) == 0 || lstrcmp("..", findResult.cFileName) == 0)
{
continue;
}
tempFolder = qFolders.front();
tempFolder.append("\\").append(findResult.cFileName);
qFolders.push(tempFolder);
}
else {
cout << findResult.cFileName << endl;
}
} while (FindNextFile(handle, &findResult));
qFolders.pop();
}
if (handle)
{
FindClose(handle);
handle = NULL;
}
}
int main()
{
QueryFileCounts("D:\\test");
return 0;
}
Edit:
There are many ways to implement queues and stacks. I recommend that you use chained queues (or chained stacks). You can find many ways to implement them on the Internet. I will provide a way of my implementation for your reference.
Here is the sample implemented in pure C:
#include <stdio.h>
#include <Windows.h>
#include <string.h>
struct Link
{
char data[1024];
struct Link* next;
};
struct Queue
{
struct Link* front;
struct Link* rear;
int size;
};
void QueueInit(struct Queue* queue)
{
queue->front = NULL;
queue->rear = NULL;
queue->size = 0;
}
int QueueEmpty(struct Queue* queue)
{
return (queue->size == 0);
}
void QueuePush(struct Queue* queue, const char * data)
{
struct Link* node;
node = (struct Link*)malloc(sizeof(struct Link));
if (node)
{
strcpy(node->data, data);
node->next = NULL;
if (QueueEmpty(queue))
{
queue->front = node;
queue->rear = node;
}
else
{
queue->rear->next = node;
queue->rear = node;
}
++queue->size;
}
}
int QueuePop(struct Queue* queue)
{
if (QueueEmpty(queue))
{
return 0;
}
struct Link* tmp = queue->front;
queue->front = queue->front->next;
free(tmp);
--queue->size;
return 1;
}
void QueueDestroy(struct Queue* queue)
{
struct Link* tmp;
while (queue->front)
{
tmp = queue->front;
queue->front = queue->front->next;
free(tmp);
}
}
void QueryFileCounts(const char * Path)
{
struct Queue qFolders;
QueueInit(&qFolders);
QueuePush(&qFolders, Path);
WIN32_FIND_DATA findResult;
HANDLE handle = NULL;
while (qFolders.size > 0)
{
char tempFolder[1024];
strcpy(tempFolder, qFolders.front->data);
sprintf(tempFolder, "%s\\*.*", tempFolder);
handle = FindFirstFile(tempFolder, &findResult);
do
{
if (findResult.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (lstrcmp(".", findResult.cFileName) == 0 || lstrcmp("..", findResult.cFileName) == 0)
{
continue;
}
strcpy(tempFolder, qFolders.front->data);
sprintf(tempFolder, "%s\\%s", tempFolder, findResult.cFileName);
QueuePush(&qFolders, tempFolder);
}
else {
printf("%s\n", findResult.cFileName);
}
} while (FindNextFile(handle, &findResult));
QueuePop(&qFolders);
}
if (handle)
{
FindClose(handle);
handle = NULL;
}
QueueDestroy(&qFolders);
}
int main()
{
QueryFileCounts("D:\\test");
return 0;
}
Upvotes: 1
Reputation: 155594
Basic approach is:
It's basically just doing the same work recursion would do for you, but limiting the scope of the stack you maintain to the directory information, without replicating the entire function stack.
Upvotes: 3