user14096327
user14096327

Reputation:

How can you iterate though directories without using any recursive functions in c?

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

Answers (2)

Zeus
Zeus

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):

  1. First add the path of this folder to a queue.
  2. 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.
  3. 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

ShadowRanger
ShadowRanger

Reputation: 155594

Basic approach is:

  1. Implement a collection (stack or queue, depending on whether you want depth or breadth first traversal) of directories to search
  2. Initialize it with the root directory to search
  3. Run a loop that runs until it's empty, popping off one directory each time, iterating its contents, and pushing on any new directories discovered during iteration into the collection (to be handled one-by-one as the loop finishes processing each directory)

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

Related Questions