You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Windows平台用C语言结合Windows.h递归搜索目录文件并存储路径

Windows平台递归搜索目录文件的C实现(适配MinGW-W64)

我们采用队列式遍历的非递归方式实现目录搜索(避免递归深度过大导致栈溢出),完全基于Windows原生API(Windows.h),适配你的MinGW-W64环境:

  • 用spaths数组作为目录队列,存放待处理的目录路径
  • 每次取出队列头部的目录,遍历其中所有项:
    • 普通文件存入files数组
    • 子目录(排除.和..)加入队列尾部等待后续处理
  • 处理完当前目录后将其从队列移除,直到队列为空

完整可运行代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

// 定义数组初始容量,可按需调整
#define INIT_DIR_CAPACITY 16
#define INIT_FILE_CAPACITY 64

// 数组动态扩容工具函数
void* realloc_array(void* arr, size_t elem_size, size_t* curr_capacity) {
    *curr_capacity *= 2;
    void* new_arr = realloc(arr, elem_size * *curr_capacity);
    if (!new_arr) {
        fprintf(stderr, "内存分配失败\n");
        exit(EXIT_FAILURE);
    }
    return new_arr;
}

int main() {
    // 初始化目录队列(spaths):存储待处理的目录路径
    WCHAR** spaths = malloc(sizeof(WCHAR*) * INIT_DIR_CAPACITY);
    size_t dir_count = 0;
    size_t dir_capacity = INIT_DIR_CAPACITY;

    // 初始化文件路径数组(files):存储找到的所有文件路径
    WCHAR** files = malloc(sizeof(WCHAR*) * INIT_FILE_CAPACITY);
    size_t file_count = 0;
    size_t file_capacity = INIT_FILE_CAPACITY;

    // 替换为你要搜索的初始目录,注意用宽字符前缀L避免中文乱码
    const WCHAR* initial_dir = L"C:\\TestDir";
    spaths[dir_count] = malloc(sizeof(WCHAR) * (wcslen(initial_dir) + 1));
    wcscpy(spaths[dir_count], initial_dir);
    dir_count++;

    // 遍历目录队列
    while (dir_count > 0) {
        // 取出队列头部目录(FIFO)
        WCHAR* curr_dir = spaths[0];
        // 移动队列元素,移除已处理的头部目录
        for (size_t i = 0; i < dir_count - 1; i++) {
            spaths[i] = spaths[i + 1];
        }
        dir_count--;

        // 构造搜索路径:目录 + "\*",用于匹配目录下所有项
        size_t dir_len = wcslen(curr_dir);
        WCHAR* search_path = malloc(sizeof(WCHAR) * (dir_len + 3)); // 预留"\*"和结束符位置
        wcscpy(search_path, curr_dir);
        // 自动补全目录末尾的反斜杠
        if (curr_dir[dir_len - 1] != L'\\') {
            wcscat(search_path, L"\\");
        }
        wcscat(search_path, L"*");

        // 启动目录项查找
        WIN32_FIND_DATAW find_data;
        HANDLE hFind = FindFirstFileW(search_path, &find_data);
        free(search_path); // 释放临时路径

        if (hFind == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "无法打开目录: %ls,错误码: %lu\n", curr_dir, GetLastError());
            free(curr_dir);
            continue;
        }

        do {
            // 跳过当前目录(.)和上级目录(..),避免循环处理
            if (wcscmp(find_data.cFileName, L".") == 0 || wcscmp(find_data.cFileName, L"..") == 0) {
                continue;
            }

            // 构造当前项的完整路径
            size_t item_len = wcslen(curr_dir) + wcslen(find_data.cFileName) + 2; // 反斜杠+结束符
            WCHAR* full_path = malloc(sizeof(WCHAR) * item_len);
            wcscpy(full_path, curr_dir);
            if (curr_dir[wcslen(curr_dir) - 1] != L'\\') {
                wcscat(full_path, L"\\");
            }
            wcscat(full_path, find_data.cFileName);

            // 判断当前项是文件还是目录
            if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                // 子目录加入队列
                if (dir_count >= dir_capacity) {
                    spaths = realloc_array(spaths, sizeof(WCHAR*), &dir_capacity);
                }
                spaths[dir_count] = full_path;
                dir_count++;
            } else {
                // 普通文件加入files数组
                if (file_count >= file_capacity) {
                    files = realloc_array(files, sizeof(WCHAR*), &file_capacity);
                }
                files[file_count] = full_path;
                file_count++;
            }

        } while (FindNextFileW(hFind, &find_data));

        // 关闭查找句柄,释放系统资源
        FindClose(hFind);
        // 释放已处理的目录路径内存
        free(curr_dir);
    }

    // 打印所有找到的文件
    printf("共找到 %zu 个文件:\n", file_count);
    for (size_t i = 0; i < file_count; i++) {
        wprintf(L"%ls\n", files[i]);
        free(files[i]);
    }

    // 释放剩余目录队列的内存(若有)
    for (size_t i = 0; i < dir_count; i++) {
        free(spaths[i]);
    }
    free(spaths);
    free(files);

    return 0;
}

代码详细解释

1. 基础定义与工具函数

  • INIT_DIR_CAPACITY/INIT_FILE_CAPACITY:设置数组初始容量,减少频繁扩容的开销
  • realloc_array:封装数组扩容逻辑,容量自动翻倍,简化内存管理

2. 数组初始化

  • spaths:宽字符指针数组,作为目录队列,遵循FIFO顺序处理目录
  • files:宽字符指针数组,存储所有找到的文件完整路径
  • 初始目录需替换为实际路径,用L前缀声明宽字符,避免中文路径乱码

3. 队列遍历逻辑

  • 每次取出队首目录处理,完成后从队列移除,确保所有目录都被遍历
  • 构造search_path时自动补全反斜杠,避免路径格式错误

4. Windows API使用

  • FindFirstFileW:启动目录查找,返回句柄并获取首个目录项信息
  • WIN32_FIND_DATAW:存储目录项属性(文件名、是否为目录等)
  • FindNextFileW:遍历后续目录项,返回FALSE表示遍历完成
  • FindClose:必须关闭查找句柄,防止系统资源泄漏

5. 内存管理

  • 所有动态分配的路径在使用完成后释放,避免内存泄漏
  • 数组满时自动扩容,确保不会因路径数量超出容量崩溃

编译与运行(MinGW-W64环境)

在VS Code终端执行以下命令(假设文件名为dir_search.c):

gcc dir_search.c -o dir_search.exe -luser32
  • -luser32:链接Windows user32库,满足Windows.hAPI的依赖

运行程序:

./dir_search.exe

运行前记得替换代码中的initial_dir为你要搜索的实际目录。

内容的提问来源于stack exchange,提问作者Samanway Karjee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 06:45:12