#pragma once
#include <string>
#include <vector>
#include <algorithm>
// SHFileOperation
#include <Shlwapi.h>
#pragma comment (lib,"Shlwapi.lib")
// iFileType,0:文件夾,1:文件
//void PrintFold(int iCurrentLevel, int iFileType, std::string strPath, std::string strFileName)
//{
// if (iFileType == 0)
// {
// printf(_T("文件夾:%d: %s\\%s\n"), iCurrentLevel, strPath.c_str(), strFileName.c_str());
// }
// else
// {
// printf(_T("文件:%d: %s\\%s\n"), iCurrentLevel, strPath.c_str(), strFileName.c_str());
// }
//}
// strPath的格式爲c:/ss/ww
// iCurrentLevel:當前文件層級,0開始
// uiEndLevel:遍歷層級深度,-1爲遍歷所有層級, 比如爲0時只遍歷當前目錄
template<class TTraverseProcess>
bool TraverseFold(std::wstring strPath, TTraverseProcess& TP, std::wstring strWildcard = _T("\\*.*"), unsigned int uiEndLevel = -1, unsigned int iCurrentLevel = 0)
{
if (iCurrentLevel > uiEndLevel)
{// 到達遍歷指定深度
return true;
}
WIN32_FIND_DATA findFileData;
std::wstring strFindPath = strPath + strWildcard; //這裏一定要指明通配符,不然不會讀取所有文件和目錄
HANDLE hFind = ::FindFirstFile(strFindPath.c_str(), &findFileData);
if (INVALID_HANDLE_VALUE == hFind) {
return false;
}
//遍歷文件夾
do
{
std::wstring strFileName = findFileData.cFileName;
if (strFileName != L"." && strFileName != L"..")
{//不是當前路徑或者父目錄的快捷方式
//printf(_T("%d: %s\\%s\n"), iCurrentLevel, strPath.c_str(), strFileName.c_str());
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{//是一個普通目錄
//設置下一個將要掃描的文件夾路徑
strFindPath = strPath + std::wstring(L"\\") + strFileName;
//遍歷該目錄
TraverseFold(strFindPath, TP, strWildcard, uiEndLevel, iCurrentLevel + 1);
// 處理函數對象
TP(iCurrentLevel, 0, strPath, strFileName);
}
else
{//是一個文件
TP(iCurrentLevel, 1, strPath, strFileName);
}
}
} while (::FindNextFile(hFind, &findFileData));//尋找下一個目錄或者文件
::FindClose(hFind);
return true;
}
// 刪除文件夾
bool KDeleteDirectory(std::wstring strDelDir, std::wstring& strErr)
{
class FindAllFiles
{
public:
void operator()(int iCurrentLevel, int iFileType, std::wstring strPath, std::wstring strFileName)
{
if (iFileType == 0)
{
//wprintf_s(L"文件夾:%d: %s\\%s\n", iCurrentLevel, strPath.c_str(), strFileName.c_str());
strFoldPathVec.push_back(std::pair<int, std::wstring>(iCurrentLevel, strPath + L"\\" + strFileName));
}
else
{
//wprintf_s(L"文件:%d: %s\\%s\n", iCurrentLevel, strPath.c_str(), strFileName.c_str());
strFilePathVec.push_back(strPath + L"\\" + strFileName);
}
}
public:
std::vector<std::wstring> strFilePathVec;
std::vector<std::pair<int, std::wstring>> strFoldPathVec;
};
//遍歷所有考試文件夾,獲取考試文件夾
FindAllFiles allFiles;
TraverseFold(strDelDir, allFiles, L"\\*.*");
for (size_t i = 0; i < allFiles.strFilePathVec.size(); ++i)
{
if (!::DeleteFile(allFiles.strFilePathVec[i].c_str()))
{
strErr = std::wstring(L"刪除文件失敗,") + allFiles.strFilePathVec[i];
return false;
}
}
std::sort(allFiles.strFoldPathVec.begin(), allFiles.strFoldPathVec.end(), [](std::pair<int, std::wstring>& lt, std::pair<int, std::wstring>& rt) {
return lt.first > rt.first;
});
for (size_t i = 0; i < allFiles.strFoldPathVec.size(); ++i)
{
if (!::RemoveDirectory(allFiles.strFoldPathVec[i].second.c_str()))
{
strErr = std::wstring(L"刪除文件夾失敗,") + allFiles.strFoldPathVec[i].second;
return false;
}
}
if (!::RemoveDirectory(strDelDir.c_str()))
{
strErr = std::wstring(L"刪除文件夾失敗,") + strDelDir;
return false;
}
return true;
}
bool KDeleteDirectorySH(std::wstring strDelDir, std::wstring& strErr)
{
SHFILEOPSTRUCTW FileOp;
FileOp.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;// | FOF_ALLOWUNDO/*刪除到回收站*/
FileOp.hNameMappings = NULL;
FileOp.hwnd = NULL;
FileOp.lpszProgressTitle = NULL;
strDelDir.push_back('\0');
FileOp.pFrom = strDelDir.c_str();
FileOp.pTo = NULL;
FileOp.wFunc = FO_DELETE;
int iReturn = SHFileOperationW(&FileOp);
if (0 != iReturn)
{
strErr = std::wstring(L"刪除文件夾失敗,") + strDelDir;
return false;
}
return true;
}
既然有SHFileOperation,爲什麼要自己遍歷文件夾呢,因爲在實際使用中發現SHFileOperation非常耗時,自己遍歷文件夾刪除完大概只要幾十毫秒,SHFileOperation則需要1秒多,很無語的,在刪除大量文件夾時就會覺得進度很慢