【问题标题】:How to delete a folder in C++?如何在 C++ 中删除文件夹?
【发布时间】:2010-10-18 14:17:45
【问题描述】:

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

如果不存在跨平台方式,那么对于最流行的操作系统——Windows、Linux、Mac、iOS、Android,如何做到这一点? POSIX 解决方案是否适用于所有人?

【问题讨论】:

    标签: c++ delete-directory


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      在 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 中
      【解决方案3】:

      在不使用 Shell API 的 Windows (VisualC++) 中删除文件夹(子文件夹和文件),这是最好的工作示例:

      #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

      【讨论】:

      • 感谢您发布不是 Boost 或对 system() 的调用的内容。
      • 但总有一天链接会失效。您是否要在答案中包含相关代码?
      • 看起来这个解决方案可能由于文件系统竞争而失败:DeleteFile 不是原子的,这意味着删除包含它的目录可能会失败,因为该目录(还)不是空的。这个演讲详细解释了这个问题,并提供了一种在 Windows 上删除目录/树的更安全的方法:youtube.com/watch?v=uhRWMGBjlO8
      • 如果 refcstrRootDirectory 或任何子文件夹有 . 作为前缀,此方法将不起作用。例如 .git。我尝试了这种方法,因为 std::filesystem::remove_all 对于具有子文件夹 .git 的文件夹失败。所以看来目前的实现也有同样的问题。
      【解决方案4】:

      目录应该是空的。

      BOOL RemoveDirectory( LPCTSTR lpPathName );
      

      【讨论】:

      • 我认为这只是 Windows?
      • 标题包含什么?
      【解决方案5】:
      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-&gt;d_name) != '.') 也应该检查“。”和“..”,目前它不会删除隐藏文件的方式。否则这很酷。
      【解决方案6】:

      使用 SHFileOperation 递归删除文件夹

      【讨论】:

        【解决方案7】:

        目录必须是空的并且你的程序必须有权限才能删除它

        但名为 rmdir 的函数会做到这一点

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

        【讨论】:

        • 你在Windows中使用什么头文件?
        • windows使用_rmdir,header是#include &lt;direct.h&gt;我相信,和_mkdir一样
        【解决方案8】:

        如果你在 linux 上也可以试试这个:

        system("rm -r path");
        

        【讨论】:

          【解决方案9】:

          这适用于删除目录中的所有目录和文件。

          #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 感谢您提出这个问题,现在我已经更新了代码。
          【解决方案10】:

          C++ 标准定义了 remove() 函数,该函数可能会或可能不会删除文件夹,具体取决于实现。如果不需要,则需要使用特定于实现的函数,例如 rmdir()。

          【讨论】:

            【解决方案11】:

            我没有评论的“声誉”,所以我必须做出回答。

            据我所知,以前的 Windows 解决方案包含一个错误(在检查“.”时:例如,它不会删除 .ssh 之类的目录)。

            此外,缺少 UTF-8 路径的(现在必须的)管理。

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

            现在我放了一个 UNIX/Linux 版本,基于以前固定的功能

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

            【讨论】:

              【解决方案12】:

              //对于windows:

              #include <direct.h>
              
              
              if(_rmdir("FILEPATHHERE") != -1)
              {
                //success     
              } else {
                //failure
              }
              

              【讨论】:

              • 这不适用于 Unicode 路径。它在大多数现代应用程序中都没有用。
              【解决方案13】:

              尝试使用系统“rmdir -s -q file_to_delte”。
              这将删除文件夹和其中的所有文件。

              【讨论】:

              • 在 POSIX 中,它不会:那里没有 -s 标志。在 Windows 上,这会尝试删除 -s-q 目录。
              【解决方案14】:

              我自己的基于 hB0 的实现,它还允许您查看每个文件夹中的文件数量,同时性能也有所提升。

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

              【讨论】:

              • 为什么转发声明DeleteDirectory?您将其声明为真正的低两行。
              【解决方案15】:

              对于 linux(我已经修复了上面代码中的错误):

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

              对于窗户:

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

              【讨论】:

                【解决方案16】:

                如果您使用的是Poco 库,这里有一种删除目录的可移植方法。

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

                remove函数在调用“true”时表示递归删除一个目录中的所有文件和子目录。

                【讨论】:

                  【解决方案17】:

                  如果您使用的是 Windows,请查看 this link。否则,您可能会寻找您的操作系统特定版本的 api。我不认为 C++ 带有跨平台的方式来做到这一点。最后,这不是 C++ 的工作,而是操作系统的工作。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2013-12-15
                    • 2017-01-06
                    • 2020-04-16
                    • 2021-07-28
                    • 2019-03-24
                    • 1970-01-01
                    • 2013-06-28
                    相关资源
                    最近更新 更多