C++ 標準庫與 MFC 僅提供刪除空目錄的 RemoveDirectory/CFileFind::RemoveDirectory。實務上常需刪除包含檔案與多層子目錄的整棵目錄樹。本文提供基於 MFC CFileFind 的遞歸刪除函式 DeleteDirectory,完整處理檔案屬性、錯誤回報與資源釋放。
// 返回值:成功 TRUE,失敗 FALSE
// 參數:DirName - 絕對路徑,如 "C:\\Temp",不可含尾隨反斜線
BOOL DeleteDirectory(char* DirName);
BOOL DeleteDirectory(char* DirName)
{
CFileFind tempFind;
char tempFileFind[200];
char foundFileName[200];
char tempPath[200];
// 1. 建立搜尋模式 "DirName\*.*"
sprintf(tempFileFind, "%s\\*.*", DirName);
// 2. 開始尋找第一個項目
BOOL IsFinded = tempFind.FindFile(tempFileFind);
while (IsFinded)
{
IsFinded = tempFind.FindNextFile();
// 跳過 "." 與 ".."
if (!tempFind.IsDots())
{
// 取得檔名(不含路徑)
strcpy(foundFileName, tempFind.GetFileName().GetBuffer(200));
if (tempFind.IsDirectory())
{
// 3. 遞歸刪除子目錄
sprintf(tempPath, "%s\\%s", DirName, foundFileName);
if (!DeleteDirectory(tempPath))
return FALSE; // 子目錄刪除失敗,向上傳播
}
else
{
// 4. 刪除檔案(先移除唯讀屬性)
sprintf(tempPath, "%s\\%s", DirName, foundFileName);
SetFileAttributes(tempPath, FILE_ATTRIBUTE_NORMAL);
if (!DeleteFile(tempPath))
return FALSE;
}
}
}
tempFind.Close();
// 5. 刪除當前目錄(此刻應已空)
if (!RemoveDirectory(DirName))
{
MessageBox(NULL, "刪除目錄失敗!", "警告", MB_OK);
return FALSE;
}
return TRUE;
}
"DirName\\*.*" 匹配目錄下所有項目(含隱藏、系統檔)。. (當前目錄) 與 .. (父目錄),避免無限遞歸。DeleteFile/RemoveDirectory 會失敗。RemoveDirectory 才能成功。
#include
#include
#include
BOOL DeleteDirectoryEx(LPCTSTR DirName, LPDWORD pErrCode = NULL)
{
TCHAR searchPath[MAX_PATH];
StringCchPrintf(searchPath, MAX_PATH, _T("%s\\*.*"), DirName);
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(searchPath, &wfd);
if (hFind == INVALID_HANDLE_VALUE)
{
if (pErrCode) *pErrCode = GetLastError();
return FALSE;
}
BOOL success = TRUE;
do
{
if (wcscmp(wfd.cFileName, _T(".")) == 0 || wcscmp(wfd.cFileName, _T("..")) == 0)
continue;
TCHAR fullPath[MAX_PATH];
StringCchPrintf(fullPath, MAX_PATH, _T("%s\\%s"), DirName, wfd.cFileName);
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (!DeleteDirectoryEx(fullPath, pErrCode))
{
success = FALSE;
break;
}
}
else
{
SetFileAttributes(fullPath, FILE_ATTRIBUTE_NORMAL);
if (!DeleteFile(fullPath))
{
if (pErrCode) *pErrCode = GetLastError();
success = FALSE;
break;
}
}
}
while (FindNextFile(hFind, &wfd));
FindClose(hFind);
if (success)
{
SetFileAttributes(DirName, FILE_ATTRIBUTE_NORMAL);
if (!RemoveDirectory(DirName))
{
if (pErrCode) *pErrCode = GetLastError();
success = FALSE;
}
}
return success;
}
| 場景 | 錯誤碼 | 對策 |
|---|---|---|
| 檔案被其他程式鎖定 | ERROR_SHARING_VIOLATION (32) | 嘗試關閉鎖定程式、重啟後再刪、或用 MoveFileEx 延遲刪除 |
| 權限不足 | ERROR_ACCESS_DENIED (5) | 以管理員身分執行、調整 ACL、或啟用 SeTakeOwnershipPrivilege |
| 路徑過長 (>260) | ERROR_FILENAME_EXCED_RANGE (206) | 使用 \\\\?\\ 前綴 + Unicode API (FindFirstFileW 等) |
| 目錄非空但 RemoveDirectory 失敗 | ERROR_DIR_NOT_EMPTY (145) | 檢查遞歸邏輯是否漏刪隱藏/系統檔 |
| 網路磁碟機延遲 | ERROR_BAD_NETPATH (53) | 重試機制、超時處理 |
#include
namespace fs = std::filesystem;
bool DeleteDirectoryModern(const std::string& path)
{
try
{
fs::remove_all(path); // 一行搞定:遞歸刪除目錄樹
return true;
}
catch (const fs::filesystem_error& e)
{
std::cerr << "Error: " << e.what() << " (code: " << e.code() << ")\n";
return false;
}
}
std::filesystem::remove_all 內部處理了屬性移除、符號連結、權限錯誤等細節,是現代 C++ 專案的首選。
無論使用 MFC、Win32 API 或 C++17 filesystem,核心邏輯皆為「深度優先遞歸:先清空內容,再刪除目錄本身」,掌握此模式即可應對各種目錄清理需求。