在 SDI 專案中結合 CFileDialog 選擇起始目錄,利用 CFileFind 遞歸掃描,可靈活實現自定義條件的文件搜尋(如:唯讀、大小範圍、擴展名等),並將結果輸出至 VC++ 輸出視窗。
#include <direct.h> // _getcwd, _chdir
void f0() {
char x[256], y[256];
CFileDialog fd(TRUE); // "File Open" 對話框
_getcwd(x, 256); // 保存當前工作目錄
if (fd.DoModal() == IDOK) {
_getcwd(y, 256); // 取得用戶選擇的目錄 (c:\windows)
f1(y); // 開始遞歸搜尋
}
_chdir(x); // 還原工作目錄
}
void f1(CString x) {
BOOL b; CFileFind f; // 局部變數支援遞歸
_chdir(x); // 切換至目標目錄
b = f.FindFile(_T("*.*")); // 查找所有文件
while (b) {
b = f.FindNextFile();
if (f.IsDirectory()) {
if (!f.IsDots()) { // 排除 "." 和 ".."
f1(f.GetFilePath()); // 遞歸進入子目錄
}
} else if (f.IsReadOnly() && f.GetLength() < 500) {
afxDump << "\n" << f.GetFilePath(); // 輸出符合條件文件
}
}
}
_getcwd/_chdir 確保遞歸過程中相對路徑正確CFileFind f 必須宣告為函數局部變數,否則遞歸層級會共用同一物件導致狀態混亂IsDots() 排除當前/父目錄,防止無限遞歸IsReadOnly() && GetLength() < 500 示範多條件邏輯afxDump 直接輸出至 VC++「輸出」視窗,便於除錯經 CMemoryState 檢測,本代碼無記憶體洩漏。關鍵在於:
CFileFind 析構時自動關閉搜尋句柄f1 放入工作執行緒,避免 UI 凍結CStringArray 或 std::vector<CString> 供後續處理virtual bool Match(const CFileFind&) 介面,支援插件式條件| 問題 | 原因 | 修正 |
|---|---|---|
| 遞歸導致棧溢位 | 目錄層級過深(>1000層) | 改用非遞歸棧/隊列實現 BFS/DFS |
| 網路路徑失敗 | _chdir 不支援 UNC 路徑 | 使用完整路徑 CFileFind::FindFile(fullPath) 避免切換目錄 |
| 權限拒絕崩潰 | 無權限讀取系統目錄 | 包裹 FindFile/FindNextFile 於 try-catch 或檢查返回值 |
本方案以 CFileDialog + CFileFind + 遞歸函數的經典組合,實現靈活可擴展的目錄樹搜尋。代碼精簡、無洩漏、易於理解與修改,是 MFC 文件系統操作的優秀教學範例與實用基礎組件。