FindFirstFile/FindNextFile) 實現,效率高。
// SearchFilesUnit.h
#ifndef SEARCH_FILES_UNIT_H
#define SEARCH_FILES_UNIT_H
#include
#include
// 回調類型定義
typedef void (__stdcall *PSEARCHCALLBACK)(LPCTSTR); // 發現文件/目錄
typedef void (__stdcall *PDIRCOMPLETEDCALLBACK)(LPCTSTR); // 目錄遍歷完成
class CSearchFile {
public:
// 無深度限制構造函數
CSearchFile() : m_depthLevel(-1) {}
// 指定最大深度構造函數 (0=僅根目錄, 1=根+一級子目錄...)
explicit CSearchFile(int depthLevel) : m_depthLevel(depthLevel) {}
// 核心搜索接口
// root: 起始目錄
// pFoundCallback: 每個文件/目錄觸發
// pDirCompletedCallback: 每個目錄遞歸返回觸發
// depthLevel: 內部遞歸用,外部調用默認 0
BOOL SearchFile(
LPCTSTR root,
PSEARCHCALLBACK pFoundCallback,
PDIRCOMPLETEDCALLBACK pDirCompletedCallback,
int depthLevel = 0
);
private:
int m_depthLevel; // -1 表示無限制
// 判斷路徑是否為目錄
BOOL DirectoryExist(LPCTSTR lpszDir);
};
#endif
// SearchFilesUnit.cpp
#include "SearchFilesUnit.h"
BOOL CSearchFile::DirectoryExist(LPCTSTR lpszDir) {
DWORD dwAttr = GetFileAttributes(lpszDir);
return (dwAttr != INVALID_FILE_ATTRIBUTES) &&
(dwAttr & FILE_ATTRIBUTE_DIRECTORY);
}
BOOL CSearchFile::SearchFile(
LPCTSTR root,
PSEARCHCALLBACK pFoundCallback,
PDIRCOMPLETEDCALLBACK pDirCompletedCallback,
int depthLevel
) {
char szPath[MAX_PATH] = {0};
WIN32_FIND_DATA wfd = {0};
sprintf(szPath, "%s\\*", root); // 搜索模式
// 深度控制:超過限制直接返回
if (m_depthLevel > 0) {
if (++depthLevel > m_depthLevel) return FALSE;
}
HANDLE hFind = FindFirstFile(szPath, &wfd);
if (hFind == INVALID_HANDLE_VALUE) return FALSE;
do {
// 跳過 "." 和 ".."
if (strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0)
continue;
char szFullPath[MAX_PATH] = {0};
sprintf(szFullPath, "%s\\%s", root, wfd.cFileName);
// 如果是目錄,遞歸進入
if (DirectoryExist(szFullPath)) {
SearchFile(szFullPath, pFoundCallback, pDirCompletedCallback, depthLevel);
}
// 文件/目錄通用回調 (業務邏輯在這裡:過濾、刪除、複製...)
if (pFoundCallback) pFoundCallback(szFullPath);
} while (FindNextFile(hFind, &wfd));
FindClose(hFind);
// 目錄遍歷完成回調 (後序:子目錄處理完後觸發)
if (pDirCompletedCallback) pDirCompletedCallback(root);
return TRUE;
}
#include "SearchFilesUnit.h"
#include
void __stdcall OnFileFound(LPCTSTR path) {
// 只處理文件,跳過目錄
DWORD attr = GetFileAttributes(path);
if (attr & FILE_ATTRIBUTE_DIRECTORY) return;
// 過濾 .tmp 後綴
const char *ext = strrchr(path, '.');
if (ext && _stricmp(ext, ".tmp") == 0) {
printf("Deleting: %s\n", path);
DeleteFile(path); // 或 MoveFile 到回收站
}
}
void __stdcall OnDirCompleted(LPCTSTR dir) {
// 可選:嘗試刪除空目錄
RemoveDirectory(dir); // 非空則失敗,安全
}
int main() {
CSearchFile searcher(3); // 最多遞歸 3 層
searcher.SearchFile("C:\\Temp", OnFileFound, OnDirCompleted);
return 0;
}
| 特性 | 實現方式 | 優勢 |
|---|---|---|
| 深度控制 | 構造函數注入 + 遞歸參數傳遞 | 靈活、無全局狀態、線程安全 |
| 關注點分離 | 雙回調機制 | 遍歷邏輯復用,業務邏輯外部化 |
| 後序處理 | 目錄完成回調 | 天然支持刪除空目錄、統計匯總 |
| Windows 原生 | FindFirstFile/FindNextFile | 無運行時依賴,性能最優 |
| 編碼處理 | LPCTSTR/TCHAR | 支援 ANSI/Unicode 雙構建 |
MAX_PATH (260) 易溢出。改用 \\\\?\\ 前綴或 GetLongPathName 支援長路徑。FindFirstFile 失敗原因未區分 (權限、不存在)。應返回錯誤碼或拋出異常。std::filesystem::recursive_directory_iterator (C++17) + std::function 回調,跨平台、類型安全、RAII 管理句柄。
#include
#include
#include
namespace fs = std::filesystem;
void SearchModern(
const fs::path& root,
int maxDepth,
std::function onFile,
std::function onDirComplete = nullptr
) {
struct StackItem { fs::path path; int depth; };
std::vector stack = {{root, 0}};
while (!stack.empty()) {
auto [cur, depth] = stack.back(); stack.pop_back();
if (depth > maxDepth) continue;
for (auto& entry : fs::directory_iterator(cur)) {
if (entry.is_directory()) {
stack.push_back({entry.path(), depth + 1});
}
onFile(entry.path());
}
if (onDirComplete) onDirComplete(cur);
}
}
C++17 版本更簡潔、跨平台、異常安全,但在極深目錄樹下棧溢出風險較大 (可改用顯式棧)。