Reputation: 57322
RemoveDirectory()
removes only empty directories. How do I remove directories that have files inside?
Upvotes: 8
Views: 14935
Reputation: 153919
Since C++17, the best solution is std::filesystem::remove_all
. Before that, you can use the Boost implementation, boost::filesystem::remove_all
. Either way, you don't have to worry about the platform-specific stuff.
I'm not aware of any other platform-independent solution; the usual way otherwise would involve reading the directory, and recursively descending it (but the way to read the directory also uses std::filesystem
, boost::filesystem
, or system-dependent code).
Upvotes: 14
Reputation:
According to MSDN, SHFileOperation
is not thread safe when used with relative paths. It can only be safely used with absolute paths.
I recommend using this code instead:
double directory_delete(char *pathname)
{
string str(pathname);
if (!str.empty())
{
while (*str.rbegin() == '\\' || *str.rbegin() == '/')
{
str.erase(str.size()-1);
}
}
replace(str.begin(),str.end(),'/','\\');
struct stat sb;
if (stat((char *)str.c_str(),&sb) == 0 &&
S_ISDIR(sb.st_mode))
{
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
TCHAR DirPath[MAX_PATH];
TCHAR FileName[MAX_PATH];
_tcscpy(DirPath,(char *)str.c_str());
_tcscat(DirPath,"\\*");
_tcscpy(FileName,(char *)str.c_str());
_tcscat(FileName,"\\");
hFind = FindFirstFile(DirPath,&FindFileData);
if (hFind == INVALID_HANDLE_VALUE) return 0;
_tcscpy(DirPath,FileName);
bool bSearch = true;
while (bSearch)
{
if (FindNextFile(hFind,&FindFileData))
{
if (!(_tcscmp(FindFileData.cFileName,".") &&
_tcscmp(FindFileData.cFileName,".."))) continue;
_tcscat(FileName,FindFileData.cFileName);
if ((FindFileData.dwFileAttributes &
FILE_ATTRIBUTE_DIRECTORY))
{
if (!directory_delete(FileName))
{
FindClose(hFind);
return 0;
}
RemoveDirectory(FileName);
_tcscpy(FileName,DirPath);
}
else
{
if (FindFileData.dwFileAttributes &
FILE_ATTRIBUTE_READONLY)
_chmod(FileName, _S_IWRITE);
if (!DeleteFile(FileName))
{
FindClose(hFind);
return 0;
}
_tcscpy(FileName,DirPath);
}
}
else
{
if (GetLastError() == ERROR_NO_MORE_FILES)
bSearch = false;
else
{
FindClose(hFind);
return 0;
}
}
}
FindClose(hFind);
return (double)(RemoveDirectory((char *)str.c_str()) == true);
}
else
{
return 0;
}
}
If you want to use my code "as-is", you will need these headers at the top of your cpp file:
#include <windows.h> // winapi
#include <sys/stat.h> // stat
#include <tchar.h> // _tcscpy,_tcscat,_tcscmp
#include <string> // string
#include <algorithm> // replace
using namespace std;
...and I think that's it.
My code is based on this article:
I strongly recommend to never use SHFileOperation
; aside from safety issues, it was replaced by IFileOperation
since Windows Vista.
Upvotes: 3
Reputation: 94329
This may be lame, but consider using
system("rd /s /q ...");
It's ugly, but it's too simple to ignore. It also has all the "how to deal with files on network shares" stuff worked out. Whatever solution you come up with is probably an (incomplete and/or incorrect) reimplementation of rd
, so calling out to the external process would actually be nice code reuse. ;-)
Upvotes: 2
Reputation: 612964
If you are prepared to use the Windows API then the easiest way to get this done is to call SHFileOperation
. Use the FO_DELETE
operation and don't forget to double null-terminate your directory name.
Upvotes: 5
Reputation: 24857
Typically, if no library method is available, this is done by recursion. A function iterates all directory entries, deleting 'ordinary' files and calling itself with any directory path found. This destroys whole directory trees, (my Windows version has explicit checks on the path passed to prevent it destroying OS folders in case of accidentally passing in a suicidal parameter).
Upvotes: 3