How to delete a folder in C++?

Viewed 134691

How can I delete a folder using C++?

If no cross-platform way exists, then how to do it for the most-popular OSes - Windows, Linux, Mac, iOS, Android? Would a POSIX solution work for all of them?

18 Answers

The directory should be empty.

BOOL RemoveDirectory( LPCTSTR lpPathName );

The directory must be empty and your program must have permissions to delete it

but the function called rmdir will do it

rmdir("C:/Documents and Settings/user/Desktop/itsme") 

The C++ Standard defines the remove() function, which may or may not delete a folder, depending on implementation. If it doesn't you need to use an implementation specific function such as rmdir().

This works for deleting all the directories and files within a directory.

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int main()
{
    cout << "Enter the DirectoryName to Delete : ";
    string directoryName;
    cin >> directoryName;
    string a = "rmdir /s /q " + directoryName;
    system(a.c_str());
    return 0;
}

I do not have the "reputation" to comment, so I have to make an answer.

As far as I could see the previous solution for Windows contains an error (in checking the ".": it does not delete directories like .ssh for example).

Furthermore, the (now necessary) management of UTF-8 paths is missing.

// OK we want the UTF-8 compatible functions
#ifndef UNICODE
#define UNICODE
#endif

#include <stdio.h>
#include <windows.h>
#include <string>
#include <assert.h>


// 16bit wide string to UTF-8 
std::string wtou(const wchar_t* i_string) 
{
    assert(sizeof(wchar_t)==2);     // Not always true 
    assert((wchar_t)(-1)==65535);   // not too big
    std::string myresult;
    if (!i_string) 
        return myresult;
    for (; *i_string; i_string++) 
    {
        if (*i_string<128) 
            myresult+=*i_string;
        else 
        if (*i_string<2048) 
            myresult+=192+*i_string/64, myresult+=128+*i_string%64;
        else 
            myresult+=224+*i_string/4096, myresult+=128+*i_string/64%64, myresult+=128+*i_string%64;
    }
    return myresult;
}

// UTF-8 to wide string
std::wstring utow(const char* i_string) 
{
    assert(sizeof(wchar_t)==2);
    assert((wchar_t)(-1)==65535);
    std::wstring myresult;
    if (!i_string) 
        return myresult;
    const unsigned char* s=(const unsigned char*)i_string;
    for (; s && *s; s++) 
    {
        if (s[0]<128) 
            myresult+=s[0];
        else 
        if (s[0]>=192 && s[0]<224 && s[1]>=128 && s[1]<192)
            myresult+=(s[0]-192)*64+s[1]-128, ++i_string;
        else 
        if (s[0]>=224 && s[0]<240 && s[1]>=128 && s[1]<192 && s[2]>=128 && s[2]<192)
            myresult+=(s[0]-224)*4096+(s[1]-128)*64+s[2]-128, s+=2;
    }
    return myresult;
}

int win_erredbarras(const std::string &i_path,bool i_flagrecursive=true)
{
    bool    flagdebug=true;
    bool    flagsubdir=false;
    HANDLE  myhandle;
    std::wstring wfilepath;
    WIN32_FIND_DATA findfiledata;

    std::string pattern=i_path+"\\*.*";
  
    std::wstring wpattern   =utow(pattern.c_str());
    std::wstring wi_path    =utow(i_path.c_str());

    myhandle=FindFirstFile(wpattern.c_str(),&findfiledata);
  
    if (myhandle!=INVALID_HANDLE_VALUE)
    {
        do
        {
            std::string t=wtou(findfiledata.cFileName);
            
            if ((t!=".") && (t!=".."))
            {
                wfilepath=wi_path+L"\\"+findfiledata.cFileName;
                if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    if (i_flagrecursive)
                    {
                        const std::string temp(wfilepath.begin(),wfilepath.end());
                        if (flagdebug)
                            printf("\n\nDelete directory   %s\n",temp.c_str());
                        int myresult=win_erredbarras(temp,i_flagrecursive);
                        if (myresult)
                            return myresult;
                    }
                    else
                        flagsubdir=true;
                }
                else
                {
                    const std::string ttemp(wfilepath.begin(), wfilepath.end() );
                    if (flagdebug)
                        printf("Try to delete file %s\n",ttemp.c_str());

                    if (SetFileAttributes(wfilepath.c_str(),FILE_ATTRIBUTE_NORMAL) == FALSE)
                    {
                        if (flagdebug)
                            printf("31019: ERROR cannot change attr of file %s\n",ttemp.c_str());
                        return GetLastError();
                    }
                    
                    if (DeleteFile(wfilepath.c_str())==FALSE)
                    {
                        if (flagdebug)
                            printf("31025: ERROR highlander file %s\n",ttemp.c_str());
                        return GetLastError();
                    }
                }
            }
        } while(FindNextFile(myhandle,&findfiledata)==TRUE);

        FindClose(myhandle);

        DWORD myerror=GetLastError();
        if (myerror==ERROR_NO_MORE_FILES)
        {
            if (!flagsubdir)
            {
                const std::string dtemp(wi_path.begin(), wi_path.end());
                
                if (flagdebug)
                    printf("Delete no subdir   %s\n",dtemp.c_str());
                            
                if (SetFileAttributes(wi_path.c_str(),FILE_ATTRIBUTE_NORMAL)==FALSE)
                {
                    if (flagdebug)
                        printf("30135: ERROR cannot change folder attr %s\n",dtemp.c_str());
                    return GetLastError();
                }
                                
                if (RemoveDirectory(wi_path.c_str())==FALSE)
                {
                    if (flagdebug)
                        printf("31047: ERROR highlander dir %s\n",dtemp.c_str());
                    return GetLastError();
                }
            }
        }
        else
            return myerror;
    }
    return 0;
}

int main()
{
    win_erredbarras("z:\\knb",true);
    return 0;
}

Now I put a UNIX/Linux version, based on fixed previous functions

#include <stdio.h>
#include <string>
#include <dirent.h>
#include <sys/stat.h>

/// secondary functions to be #ifdeffed on Windows
bool isdirectory(std::string i_filename)
{
    if (i_filename.length()==0)
        return false;
    else
        return i_filename[i_filename.size()-1]=='/';
}
bool delete_file(const char* i_filename) 
{
    return remove(i_filename)==0;
}
bool delete_dir(const char* i_directory) 
{
    return remove(i_directory)==0;
}

int erredbarras(const std::string &i_path,bool i_flagrecursive=true)
{
    bool    flagdebug=true;
    bool    risultato=false;

    DIR *d=opendir(i_path.c_str());

    if (d) 
    {
        struct dirent *p;
        risultato=true;
        while (risultato && (p=readdir(d))) 
        {
            if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
                continue;
            bool risultato2=false;
            struct stat statbuf;
            
            std::string temp;
            if (isdirectory(i_path))
                temp=i_path+p->d_name;
            else
                temp=i_path+"/"+p->d_name;

            if (!stat(temp.c_str(), &statbuf)) 
            {
                if (S_ISDIR(statbuf.st_mode))
                    risultato2=erredbarras(temp);
                else
                {
                    if (flagdebug)
                        printf("Delete file %s\n",temp.c_str());
                    risultato2=delete_file(temp.c_str());
                }
            }
            risultato=risultato2;
        }
        closedir(d);
    }

    if (risultato)
    {
        if (flagdebug)
            printf("Delete dir  %s\n\n",i_path.c_str());
        delete_dir(i_path.c_str());
    }
   return risultato;
}


int main()
{
    printf("Risultato %d\n",erredbarras("/tmp/knb/"));
    return 0;
}

For linux (I have fixed bugs in code above):

void remove_dir(char *path)
{
        struct dirent *entry = NULL;
        DIR *dir = NULL;
        dir = opendir(path);
        while(entry = readdir(dir))
        {   
                DIR *sub_dir = NULL;
                FILE *file = NULL;
                char* abs_path new char[256];
                 if ((*(entry->d_name) != '.') || ((strlen(entry->d_name) > 1) && (entry->d_name[1] != '.')))
                {   
                        sprintf(abs_path, "%s/%s", path, entry->d_name);
                        if(sub_dir = opendir(abs_path))
                        {   
                                closedir(sub_dir);
                                remove_dir(abs_path);
                        }   
                        else 
                        {   
                                if(file = fopen(abs_path, "r"))
                                {   
                                        fclose(file);
                                        remove(abs_path);
                                }   
                        }   
                }
                delete[] abs_path;   
        }   
        remove(path);
}

For windows:

void remove_dir(const wchar_t* folder)
{
    std::wstring search_path = std::wstring(folder) + _T("/*.*");
    std::wstring s_p = std::wstring(folder) + _T("/");
    WIN32_FIND_DATA fd;
    HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                if (wcscmp(fd.cFileName, _T(".")) != 0 && wcscmp(fd.cFileName, _T("..")) != 0)
                {
                    remove_dir((wchar_t*)(s_p + fd.cFileName).c_str());
                }
            }
            else {
                DeleteFile((s_p + fd.cFileName).c_str());
            }
        } while (::FindNextFile(hFind, &fd));
        ::FindClose(hFind);
        _wrmdir(folder);
    }
}

If you are using the Poco library, here is a portable way to delete a directory.

#include "Poco/File.h"
...
...
Poco::File fooDir("/path/to/your/dir");
fooDir.remove(true);

The remove function when called with "true" means recursively delete all files and sub directories in a directory.

In order to delete a directory and all the contents of directory (its subdirectories recursively) and in the end delete directory itself use remove_all from standard library.

std::filesystem::remove_all(directory);

If you are using windows, then take a look at this link. Otherwise, you may look for your OS specific version api. I don't think C++ comes with a cross-platform way to do it. At the end, it's NOT C++'s work, it's the OS's work.

Related