How to delete a folder in C++?
Asked Answered
I

18

62

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?

Icily answered 9/4, 2009 at 15:26 Comment(0)
P
70

With C++17 you can use std::filesystem, in C++14 std::experimental::filesystem is already available. Both allow the usage of filesystem::remove().

C++17:

#include <filesystem>
std::filesystem::remove("myEmptyDirectoryOrFile"); // Deletes empty directories or single files.
std::filesystem::remove_all("myDirectory"); // Deletes one or more files recursively.

C++14:

#include <experimental/filesystem>
std::experimental::filesystem::remove("myDirectory");

Note 1: Those functions throw filesystem_error in case of errors. If you want to avoid catching exceptions, use the overloaded variants with std::error_code as second parameter. E.g.

std::error_code errorCode;
if (!std::filesystem::remove("myEmptyDirectoryOrFile", errorCode)) {
    std::cout << errorCode.message() << std::endl;
}

Note 2: The conversion to std::filesystem::path happens implicit from different encodings, so you can pass strings to filesystem::remove().

Phile answered 13/4, 2017 at 12:58 Comment(1)
Thanks for letting us know that this is in std::filesystem now in C++14/17Kennard
T
62

I strongly advise to use Boost.FileSystem.

http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm

In your case that would be

boost::filesystem::remove_all(yourPath)

Twit answered 9/4, 2009 at 15:36 Comment(0)
I
23

Delete folder (sub_folders and files) in Windows (VisualC++) not using Shell APIs, this is the best working sample:

#include <string>
#include <iostream>

#include <windows.h>
#include <conio.h>


int DeleteDirectory(const std::string &refcstrRootDirectory,
                    bool              bDeleteSubdirectories = true)
{
  bool            bSubdirectory = false;       // Flag, indicating whether
                                               // subdirectories have been found
  HANDLE          hFile;                       // Handle to directory
  std::string     strFilePath;                 // Filepath
  std::string     strPattern;                  // Pattern
  WIN32_FIND_DATA FileInformation;             // File information


  strPattern = refcstrRootDirectory + "\\*.*";
  hFile = ::FindFirstFile(strPattern.c_str(), &FileInformation);
  if(hFile != INVALID_HANDLE_VALUE)
  {
    do
    {
      if(FileInformation.cFileName[0] != '.')
      {
        strFilePath.erase();
        strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName;

        if(FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
          if(bDeleteSubdirectories)
          {
            // Delete subdirectory
            int iRC = DeleteDirectory(strFilePath, bDeleteSubdirectories);
            if(iRC)
              return iRC;
          }
          else
            bSubdirectory = true;
        }
        else
        {
          // Set file attributes
          if(::SetFileAttributes(strFilePath.c_str(),
                                 FILE_ATTRIBUTE_NORMAL) == FALSE)
            return ::GetLastError();

          // Delete file
          if(::DeleteFile(strFilePath.c_str()) == FALSE)
            return ::GetLastError();
        }
      }
    } while(::FindNextFile(hFile, &FileInformation) == TRUE);

    // Close handle
    ::FindClose(hFile);

    DWORD dwError = ::GetLastError();
    if(dwError != ERROR_NO_MORE_FILES)
      return dwError;
    else
    {
      if(!bSubdirectory)
      {
        // Set directory attributes
        if(::SetFileAttributes(refcstrRootDirectory.c_str(),
                               FILE_ATTRIBUTE_NORMAL) == FALSE)
          return ::GetLastError();

        // Delete directory
        if(::RemoveDirectory(refcstrRootDirectory.c_str()) == FALSE)
          return ::GetLastError();
      }
    }
  }

  return 0;
}


int main()
{
  int         iRC                  = 0;
  std::string strDirectoryToDelete = "c:\\mydir";


  // Delete 'c:\mydir' without deleting the subdirectories
  iRC = DeleteDirectory(strDirectoryToDelete, false);
  if(iRC)
  {
    std::cout << "Error " << iRC << std::endl;
    return -1;
  }

  // Delete 'c:\mydir' and its subdirectories
  iRC = DeleteDirectory(strDirectoryToDelete);
  if(iRC)
  {
    std::cout << "Error " << iRC << std::endl;
    return -1;
  }

  // Wait for keystroke
  _getch();

  return 0;
}

Source: http://www.codeguru.com/forum/showthread.php?t=239271

Inflexible answered 31/5, 2012 at 15:3 Comment(4)
Thank you for posting something that was not Boost or a call to system().Helfant
But one day the link will be dead. Are you going to include the relevant code in the answer?Helenhelena
It looks like this solution can fail due to filesystem races: DeleteFile is not atomic, which means deleting the directory that contained it can fail because the directory isn't (yet) empty. This talk explains the problem in detail and gives a safer way to delete a directory/tree on Windows: youtube.com/watch?v=uhRWMGBjlO8Woolgathering
This method will not work if refcstrRootDirectory or any subfolder has a . as prefix. For example .git. I tried this method because std::filesystem::remove_all failed for folders with a subfolder .git. So it seems that the current implementation has the same problem.Merridie
H
10

The directory should be empty.

BOOL RemoveDirectory( LPCTSTR lpPathName );
Hermosa answered 9/4, 2009 at 15:32 Comment(2)
This is Windows only I think?Menard
what included for the header ?Carn
M
10
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[100] = {0};
                if(*(entry->d_name) != '.')
                {   
                        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);
                                }   
                        }   
                }   
        }   
        remove(path);
}
Mitsukomitt answered 22/12, 2014 at 14:2 Comment(1)
if path ends with a '/' then only the /content/ should be deleted and the - now empty - directory itself should remain; also if(*(entry->d_name) != '.') should check for "." and "..", the way it is currently it will not delete hidden files. otherwise this is cool.King
E
5

Use SHFileOperation to remove the folder recursivelly

Ensanguine answered 6/11, 2012 at 17:28 Comment(0)
H
4

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") 
Heliocentric answered 9/4, 2009 at 15:31 Comment(2)
What header file do you use in Windows?Commute
use _rmdir for windows, and the header is #include <direct.h> I believe, same as _mkdirLisettelisha
R
4

You can also try this if you are on linux:

system("rm -r path");
Rundell answered 8/1, 2013 at 6:54 Comment(0)
G
4

[C++ 17]

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);
Greyback answered 21/7, 2022 at 17:20 Comment(1)
For some pre-C++ 17 scenarios, std::experimental::filesystem might be available - #53366038Photoengraving
B
2

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;
}
Bust answered 2/2, 2020 at 19:36 Comment(3)
no need to use char_array, c_str is sufficient. Otherwise this could lead to a buffer overflow if the string "a" contains more than 99 characters.Knobloch
@Knobloch Thanks for bringing the issue, Now I've updated the code.Bust
Not a clean solution - rather hack that works for Windows. Secondly - it is not cross-platformCru
T
1

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().

Turki answered 9/4, 2009 at 15:29 Comment(0)
F
1

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;
}
Fachanan answered 10/6, 2021 at 12:15 Comment(0)
C
0

//For windows:

#include <direct.h>


if(_rmdir("FILEPATHHERE") != -1)
{
  //success     
} else {
  //failure
}
Cradling answered 1/6, 2012 at 3:2 Comment(1)
This doesn't work for Unicode paths. It's not useful in most modern applications.Stricklan
P
0

My own implementation based off hB0 that also allows you to view the number of files in each folder also with a little performance boost.

#include <string>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <windows.h>
#include <conio.h>

union seperated {
  struct {
    unsigned int low;
    unsigned int high;
  } uint;
  unsigned long long ull;
};

unsigned long long num_dirs  = 1;
unsigned long long num_files = 0;
seperated size_files;

int DeleteDirectory( char* refRootDirectory );      //predeclare it

int DeleteDirectory( char* refRootDirectory ) {
    HANDLE      hFile;              // Handle to directory
    std::string strFilePath;            // Filepath
    WIN32_FIND_DATA FileInformation;    // File information
    int     dwError;            // Folder deleting error
    std::string strPattern;         // Pattern

    strPattern = (std::string)(refRootDirectory) + "\\*.*";
    hFile = ::FindFirstFile( strPattern.c_str(), &FileInformation );

    if( hFile != INVALID_HANDLE_VALUE )
    {
        do {
            if( FileInformation.cFileName[0] != '.' ) {
                strFilePath.erase();
                strFilePath = std::string(refRootDirectory) + "\\" + FileInformation.cFileName;

                if( FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
                    DeleteDirectory( (char*)strFilePath.c_str() );

                    dwError = ::GetLastError();
                    if( dwError != ERROR_NO_MORE_FILES ) {
                        std::cout << "!ERROR!: [[" << strFilePath.c_str() << "]]\n";
                        return dwError;
                    } else {
                        // Set directory attributes
                        if( ! ::SetFileAttributes(refRootDirectory,FILE_ATTRIBUTE_NORMAL) ) {
                            std::cout << "!ERROR!: [[" << strFilePath.c_str() << "]]\n";
                            return ::GetLastError();
                        }

                        // Delete directory
                        if( ! ::RemoveDirectory(refRootDirectory) ) {
                            std::cout << "!ERROR!: [[" << strFilePath.c_str() << "]]\n";
                            return ::GetLastError();
                        }
                    }

                    ++num_dirs;
                } else {

                    // Set file attributes
                    if( ! ::SetFileAttributes(strFilePath.c_str(),FILE_ATTRIBUTE_NORMAL) ) {
                        std::cout << "!ERROR!: [[" << strFilePath.c_str() << "]]\n";
                        return ::GetLastError();
                    }

                    // Delete file
                    if ( ! ::DeleteFile(strFilePath.c_str()) ) {
                        std::cout << "!ERROR!: [[" << strFilePath.c_str() << "]]\n";
                        return ::GetLastError();
                    }

                    size_files.ull       += FileInformation.nFileSizeLow;
                    size_files.uint.high += FileInformation.nFileSizeHigh;

                    ++num_files;
                }
            }
        } while( ::FindNextFile(hFile,&FileInformation) );

        // Close handle
        ::FindClose( hFile  );
    }

    return 0;
}

unsigned long long num_files_total=0;
unsigned long long num_dirs_total=0;
unsigned long long total_size_files=0;

void my_del_directory( char* dir_name ) {
    int iRC = DeleteDirectory( dir_name );
    //int iRC=0;

    std::cout << "\"" << dir_name << "\""
             "\n    Folders: " << num_dirs
          << "\n    Files:   " << num_files
          << "\n    Size:    " << size_files.ull << " Bytes";
    if(iRC)
    {
        std::cout << "\n!ERROR!: " << iRC;
    }
    std::cout << "\n\n";

    num_dirs_total   += num_dirs;
    num_files_total  += num_files;
    total_size_files += size_files.ull;
    num_dirs  = 1;
    num_files = 0;
    size_files.ull = 0ULL;
    return;
}

int main( void )
{
    size_files.ull = 0ULL;

    my_del_directory( (char*)"C:\Windows\temp"      );
        // This will clear out the System temporary directory on windows systems

    std::cout << "\n\nResults" << "\nTotal Folders: " << num_dirs_total
                   << "\nTotal Files:   " << num_files_total
                   << "\nTotal Size:    " << total_size_files << " Bytes\n";

    return 0;
}
Prier answered 19/9, 2016 at 0:27 Comment(1)
Why forward declare DeleteDirectory? You declare it for real two lines lower.Swanner
S
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);
    }
}
Slothful answered 8/6, 2018 at 17:44 Comment(0)
U
0

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.

Urano answered 7/6, 2019 at 3:34 Comment(0)
B
-1

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.

Breunig answered 9/4, 2009 at 15:35 Comment(0)
E
-1

Try use system "rmdir -s -q file_to_delte".
This will delete the folder and all files in it.

Eaddy answered 26/2, 2013 at 8:48 Comment(1)
In POSIX, it won't: there's no -s flag there. On windows, this attempts to remove the -s and -q directories.Paragrapher

© 2022 - 2024 — McMap. All rights reserved.