NullPoiиteя
NullPoiиteя

Reputation: 57322

How do I remove a directory recursively?

RemoveDirectory() removes only empty directories. How do I remove directories that have files inside?

Upvotes: 8

Views: 14935

Answers (5)

James Kanze
James Kanze

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

user4821390
user4821390

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:

http://www.codeguru.com/cpp/w-p/files/folderdirectorymaintenance/article.php/c8999/Deleting-a-Directory-Along-with-SubFolders.htm

I strongly recommend to never use SHFileOperation; aside from safety issues, it was replaced by IFileOperation since Windows Vista.

Upvotes: 3

Frerich Raabe
Frerich Raabe

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

David Heffernan
David Heffernan

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

Martin James
Martin James

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

Related Questions