如何在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
相关产品推荐
相关产品推荐

