4

In C++, how can I remove a directory with all its contained files? I know there is rmdir, but it will only remove non-empty directories, so how do I list and remove all contained files first?

I know it shouldn't be hard using Boost Filesystem, but I kind of want to avoid building and depending on it just for this one little task ...

Frank
  • 64,140
  • 93
  • 237
  • 324
  • What platform is this for? `rmdir` suggests Unix or Linux to me. – David Thornley Jul 19 '10 at 20:08
  • 1
    @David: Yes, I forgot to mention I'm on Linux. (But rmdir is platform-independent?) But it looks like maybe it's better to use Boost after all ... – Frank Jul 19 '10 at 20:08
  • If you really want to do file manipulation with C++ use boost. If shell commands are enough use `rm -rf [dirname]`. – pmr Jul 19 '10 at 20:16
  • @dehmann: not exactly "platform-indendent", but "commonly used" (ie, both Unix/Linux & DOS, maybe others -- Does Mac OSX have a command-line interface?) – James Curran Jul 19 '10 at 20:22
  • @James: yes -- the default used to be tcsh, but it changed to Bash a few years ago. Most of the other usual suspects are available as well. – Jerry Coffin Jul 19 '10 at 20:28

4 Answers4

8

Yes, you normally have to remove the contents first. If you don't want to use Boost for this, you're pretty much stuck with writing non-portable code to find all the files (e.g., FindFirstFile, FindNextFile on Windows, opendir, readdir on Unix and similar) recursively, and remove all of them.

On Windows, you can also use ShFileOperation or the IFileOperation interface. These can handle a recursive delete internally, so you just give it the name of the directory you want removed, and it handles the rest.

As with most COM things, the IFileOperation interface seems to be designed specifically to be as clumsy as possible (e.g., IFileOperation::DeleteItem doesn't actually delete anything--it just adds an item to a list of things to be deleted. Then you have to call IFileOperation::PerformOperations to do the actual deletion.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
5

You can use the following code to delete a non-empty directory. This uses Unix-style commands but can be compiled for Windows using Cygwin (if you don't mind depending on the Cygwin DLL).

void delete_folder_tree (const char* directory_name) {
    DIR*            dp;
    struct dirent*  ep;
    char            p_buf[512] = {0};

    dp = opendir(directory_name);

    while ((ep = readdir(dp)) != NULL) {
        sprintf(p_buf, "%s/%s", directory_name, ep->d_name);
        if (path_is_directory(p_buf))
            delete_folder_tree(p_buf);
        else
            unlink(p_buf);
    }

    closedir(dp);
    rmdir(directory_name);
}

int path_is_directory (const char* path) {
    struct stat s_buf;

    if (stat(path, &s_buf))
        return 0;

    return S_ISDIR(s_buf.st_mode);
}
bta
  • 43,959
  • 6
  • 69
  • 99
  • Please use this: "if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) continue;" Otherwise you'll get infinite loop on . (self dir) – mafonya Aug 16 '17 at 13:23
1

You'll need to loop over all the files in the directory and delete those first. The code is platform dependent though (as others have mentioned).

For example the code on this MSDN page (from which this is extracted so there will be undefined variables) will work for Windows, but not Unix/Linux:

HANDLE hFind = FindFirstFile(szDir, &ffd);

if (INVALID_HANDLE_VALUE == hFind) 
{
    DisplayErrorBox(TEXT("FindFirstFile"));
    return dwError;
} 

// List all the files in the directory with some info about them.
do
{
    if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    {
        _tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);
    }
    else
    {
        filesize.LowPart = ffd.nFileSizeLow;
        filesize.HighPart = ffd.nFileSizeHigh;
        _tprintf(TEXT("  %s   %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
    }
}
while (FindNextFile(hFind, &ffd) != 0);

dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES) 
{
    DisplayErrorBox(TEXT("FindFirstFile"));
}

FindClose(hFind);

prints the file information, but adapting it to delete shouldn't be too hard.

You'll need to call this recursively for all sub directories in the tree.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
1

First of all, any file i/o -- particularly directory changes, is very much OS dependent.

But, for the most part, it's a) deleted the files, then b) remove the directory. (any shortcut to that would definitely be OS dependent, and often OS version depedent)

James Curran
  • 101,701
  • 37
  • 181
  • 258