c - 尝试递归循环文件夹内容

标签 c file recursion directory count

我正在尝试创建一个递归返回文件夹内容的函数。在测试时,我遇到了一些问题。对于某些文件夹,它可以工作,对于其他文件夹,它会给我一个 EXC_BAD_ACCESS,有时它会停止。

很长一段时间以来,我一直在尝试使用 GDB 对其进行调试,但我就是找不到解决问题的方法。该函数并没有退出,而是如下所示。

#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>

/* THIS IS AN EXTRACT FROM A LARGER FILE
 THERE MAY BE TO MUCH INCLUDE STATEMENTS
 */

struct Directory {
    DIR *handle;
    const char *filename;
};
typedef struct Directory Directory;

int DirectoryCreate(const char *n, Directory *d) {
    DIR *dh;
    char *str;

    dh = opendir(n);
    if(dh == NULL) {
        return -1;
    }

    d->handle = dh;
    str = malloc(strlen(n) + 1);
    if(str == NULL) {
        errno = ENOMEM;
        closedir(d->handle);
        return -1;
    }
    strcpy(str, n);
    d->filename = (const char *)str;
    return 0;
}

void DirectoryFree(Directory *s) {
    if(s->handle) {
        closedir(s->handle);
    }
    if(s->filename) {
        free((void *)s->filename);
    }
}

void FreeDirectoryArray(Directory *array, size_t size) {
    register size_t i;
    for(i = 0; i < size; i++) {
        DirectoryFree(&(array[i]));
    }

    free(array);
}

Directory *ReadFolders = NULL;
size_t ReadFoldersSize = 0;
const char *ReadFolderFilename = NULL;
const char *ReadNextRecursiveItemInFolder(const char *folder) {
    struct dirent *entry;
    struct stat fileStatus;
    int status;
    mode_t mode;
    const char *newFilename;
    char *fullName;
    char *ptr;
    size_t strLen;

    if(folder == NULL && ReadFolders == NULL) {
        errno = 0;
        return NULL;
    }

    if(folder != NULL) {
        /* free the previous directory list */
        FreeDirectoryArray(ReadFolders, ReadFoldersSize);
        ReadFolders = NULL;
        ReadFoldersSize = 0;

        /* open the new directory */
        ReadFolders = (Directory *)realloc(ReadFolders, sizeof(Directory));
        ReadFoldersSize++;
        status = DirectoryCreate(folder, ReadFolders);
        if(status != 0) {
            FreeDirectoryArray(ReadFolders, ReadFoldersSize-1);
            ReadFolders = NULL;
            return NULL;
        }
    }

    entry = readdir(ReadFolders[ReadFoldersSize - 1].handle);
    /* If NULL, go to previous folder */
    if(entry == NULL) {
        DirectoryFree(&(ReadFolders[ReadFoldersSize - 1]));
        --ReadFoldersSize;

        /* if it's empty, we've reached the end */
        if(ReadFoldersSize == 0) {
            free(ReadFolders);
            ReadFolders = NULL;
            errno = 0;
            return NULL;
        }

        newFilename = ReadNextRecursiveItemInFolder(NULL);
        return newFilename;
    }
    /* Make sure the entry name is not . or .. */
    if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
        newFilename = ReadNextRecursiveItemInFolder(NULL);
        return newFilename;
    }

    /* we've got an entry, now construct the full path */
    strLen = 
        strlen(ReadFolders[ReadFoldersSize - 1].filename) +
        1 +
        strlen(entry->d_name);
    fullName = malloc(strLen + 1);
    ptr = fullName;
    strcpy(ptr, ReadFolders[ReadFoldersSize - 1].filename);
    ptr += strlen(ReadFolders[ReadFoldersSize - 1].filename);
    strcpy(ptr, "/");
    ptr++;
    strcpy(ptr, entry->d_name);
    newFilename = fullName;

    /* no recurse on symbolic links */
    status = lstat(newFilename, &fileStatus);
    if(status != 0) {
        FreeDirectoryArray(ReadFolders, ReadFoldersSize);
        ReadFolders = NULL;
        ReadFoldersSize = 0;
        return NULL;
    }

    mode = fileStatus.st_mode;
    /* if not readable for file or not searchable for folder, get next */
    /* if folder and not link, recursively continue */
    /* else  return the new name */
    if((((mode & S_IFDIR) == S_IFDIR) && (mode & S_IXUSR) != S_IXUSR) || 
        (mode & S_IRUSR) != S_IRUSR) {
        free((void *)newFilename);
        newFilename = ReadNextRecursiveItemInFolder(NULL);
        return newFilename;

    } else if((mode & S_IFDIR) && (mode & S_IFLNK) != S_IFLNK) {
        ReadFolders = realloc(ReadFolders, ReadFoldersSize + 1);
        ReadFoldersSize++;
        errno = 0;
        status = DirectoryCreate(newFilename, &(ReadFolders[ReadFoldersSize - 1]));
        if(status != 0) {
            FreeDirectoryArray(ReadFolders, ReadFoldersSize - 1);
            ReadFolders = NULL;
            ReadFoldersSize = 0;
            return NULL;
        }

        if(newFilename != ReadFolderFilename) {
            free((void *)ReadFolderFilename);
            ReadFolderFilename = newFilename;
        }

    } else {
        if(newFilename != ReadFolderFilename) {
            free((void *)ReadFolderFilename);
            ReadFolderFilename = newFilename;
        }
        errno = 0;
    }

    return ReadFolderFilename;
}

int main() {
    const char *filename = "/Users/";
    const char *entry;

    while(1) {
        entry = ReadNextRecursiveItemInFolder(filename);
        filename = NULL;
        if(entry == NULL) {
            if(errno == 0) {
                printf("End reached\n");
            } else {
                printf("Error: %s\n", strerror(errno));
            }
            break;
        }

        printf("Entry: %s\n", entry);
    }

    return 0;
}

我将简要说明代码的工作原理。要开始循环目录,您必须为该函数提供完整的目录路径。所有后续调用都必须传递 NULL 以获取行中的下一项,除非它们想要处理另一个目录。

代码递归地计算文件夹中的每个文件和文件夹。它不遵循符号链接(symbolic link),只计算可读文件和可执行目录。为了跟踪其“流程”,该函数使用了 3 个全局变量:

  • ReadFolders:Directory 结构数组,用于跟踪不同级别的文件夹。最后一个在后面。
  • ReadFoldersSize:ReadFolders 中Directory 结构的数量。
  • ReadFolderFilename:包含最后处理的项目的字符串。

我希望我能在这里找到一些帮助, ief2.

最佳答案

重新分配大小错误:不是“n”而是“n*size”。

所以第 153 行应该是:

ReadFolders = realloc(ReadFolders, (ReadFoldersSize + 1)*sizeof(Directory));

关于c - 尝试递归循环文件夹内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4538801/

相关文章:

c++ - 使用 CreateFile 打开文件*

java - 是否可以将 Java 应用程序设置为默认文件打开器?

c++ - bool递归函数中的真/假优先级

java - 如何使用递归对 ArrayList<Integers> 求和?

c - 二叉树是否包含在另一棵二叉树中 - C

c - 我如何确定是否可以在 C 中计算 x+y 而不会溢出?

javascript - 如何使我的 C 程序运行得更快?

c - 特殊字符读取错误 - 文件 I/0

c - C 语言的文件处理计算

java - 子集求和解java