如何在C++中删除一个文件夹?

59

如何使用C++删除文件夹?

如果没有跨平台的解决方案,那么如何在最流行的操作系统Windows、Linux、Mac、iOS和Android中实现呢?POSIX解决方案是否适用于所有这些操作系统?

18个回答

65

在C++17中,您可以使用std::filesystem,而在C++14中已经有std::experimental::filesystem可用。两者都允许使用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");

注意1: 这些函数在发生错误时会抛出filesystem_error异常。如果你想避免捕获异常,可以使用带有std::error_code作为第二个参数的重载版本。例如:

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

注意2: 从不同的编码隐式地转换为std::filesystem::path,因此您可以将字符串传递给filesystem::remove()


感谢您告诉我们这现在在C++14/17的std::filesystem中。 - Jesse

62

23

在Windows(VisualC ++)中删除文件夹(子文件夹和文件),而不使用Shell API,这是最佳工作样本:

#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;
}

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

(注:该链接为文章来源)

7
谢谢您发布的不是Boost或system()调用的内容。 - Ed Bayiates
但是总有一天这个链接会失效。你会在回答中包含相关的代码吗? - jogojapan
看起来这个解决方案可能会由于文件系统竞争而失败:DeleteFile不是原子的,这意味着删除包含它的目录可能会失败,因为该目录(尚)不为空。这篇演讲详细解释了问题,并提供了在Windows上删除目录/树的更安全方式:https://www.youtube.com/watch?v=uhRWMGBjlO8 - Adrian McCarthy
1
如果refcstrRootDirectory或任何子文件夹以*.*作为前缀,则此方法将无法正常工作。例如.git。我尝试使用此方法,因为std::filesystem::remove_all无法删除具有子文件夹.git的文件夹。因此,当前实现似乎存在相同的问题。 - Mathias Hölzl

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);
}

如果path/结尾,则只删除/content/,并保留空目录本身;另外,if(*(entry->d_name) != '.')应该检查"."和"..",因为当前的方式不会删除隐藏文件。否则这很好。 - slashmais

10
目录应该是空的。
BOOL RemoveDirectory( LPCTSTR lpPathName );

17
这是仅适用于Windows系统的吧? - Aardvark
头文件中包含了什么? - gumuruh

5
使用SHFileOperation递归删除文件夹。

4
目录必须为空,并且您的程序必须具有删除权限,但名为rmdir的函数将执行此操作。
rmdir("C:/Documents and Settings/user/Desktop/itsme") 

4
在Windows中,你使用哪个头文件? - Mark Lakata
使用_rmdir用于Windows,头文件是#include <direct.h>,我相信与_mkdir相同。 - Mich

3
如果您在Linux系统上,也可以尝试以下方法:
system("rm -r path");

2
为了删除一个目录以及其所有内容(递归地删除其子目录),最后删除该目录本身,请使用标准库中的remove_all函数。
std::filesystem::remove_all(directory);

1
对于一些 C++ 17 之前的情况,可能会有 std::experimental::filesystem 可用 - https://dev59.com/DVQJ5IYBdhLWcg3wqnwT - GTAE86

2
这适用于删除目录中的所有子目录和文件。
#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;
}

请勿使用char_array, 使用c_str即可。否则,如果字符串"a"包含99个以上的字符,则会导致缓冲区溢出。 - Aminos
1
@Aminos 感谢您提出这个问题,现在我已经更新了代码。 - Akash Kumar Singhal
不是一个干净的解决方案 - 而是在Windows上运作的hack。第二点是 - 它不是跨平台的。 - Adam Kuzański

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接