【问题标题】:How do I remove a directory that is not empty?如何删除非空目录?
【发布时间】:2010-12-11 20:17:20
【问题描述】:

我正在尝试删除带有rmdir 的目录,但我收到了“目录不是空的”消息,因为其中仍有文件。

我可以使用什么函数来删除包含所有文件的目录?

【问题讨论】:

标签: php directory


【解决方案1】:

没有内置函数可以执行此操作,但请参阅http://us3.php.net/rmdir 底部的 cmets。许多评论者发布了他们自己的递归目录删除功能。您可以从中挑选。

这里是one that looks decent

function deleteDirectory($dir) {
    if (!file_exists($dir)) {
        return true;
    }

    if (!is_dir($dir)) {
        return unlink($dir);
    }

    foreach (scandir($dir) as $item) {
        if ($item == '.' || $item == '..') {
            continue;
        }

        if (!deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) {
            return false;
        }

    }

    return rmdir($dir);
}

如果你想保持简单,你可以调用rm -rf。这确实使您的脚本仅适用于 UNIX,因此请注意这一点。如果你走那条路,我会尝试类似:

function deleteDirectory($dir) {
    system('rm -rf -- ' . escapeshellarg($dir), $retval);
    return $retval == 0; // UNIX commands return zero on success
}

【讨论】:

  • 这非常危险,请添加检查以确保您没有删除重要的内容,例如 /..
【解决方案2】:
function rrmdir($dir)
{
 if (is_dir($dir))
 {
  $objects = scandir($dir);

  foreach ($objects as $object)
  {
   if ($object != '.' && $object != '..')
   {
    if (filetype($dir.'/'.$object) == 'dir') {rrmdir($dir.'/'.$object);}
    else {unlink($dir.'/'.$object);}
   }
  }

  reset($objects);
  rmdir($dir);
 }
}

【讨论】:

    【解决方案3】:

    您总是可以尝试使用系统命令。

    如果在 linux 上使用:rm -rf /dir 如果在 Windows 上使用:rd c:\dir /S /Q

    在上面的帖子 (John Kugelman) 中,我认为 PHP 解析器会优化 foreach 中的 scandir,但在 foreach 条件语句中使用 scandir 对我来说似乎是错误的。
    您也可以只执行两个array_shift 命令来删除...,而不是总是检查循环。

    【讨论】:

      【解决方案4】:

      想不出比这更简单、更有效的方法

      function removeDir($dirname) {
          if (is_dir($dirname)) {
              $dir = new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS);
              foreach (new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST) as $object) {
                  if ($object->isFile()) {
                      unlink($object);
                  } elseif($object->isDir()) {
                      rmdir($object);
                  } else {
                      throw new Exception('Unknown object type: '. $object->getFileName());
                  }
              }
              rmdir($dirname); // Now remove myfolder
          } else {
              throw new Exception('This is not a directory');
          }
      }
      
      
      removeDir('./myfolder');
      

      【讨论】:

        【解决方案5】:

        这是我用的:

        function emptyDir($dir) {
            if (is_dir($dir)) {
                $scn = scandir($dir);
                foreach ($scn as $files) {
                    if ($files !== '.') {
                        if ($files !== '..') {
                            if (!is_dir($dir . '/' . $files)) {
                                unlink($dir . '/' . $files);
                            } else {
                                emptyDir($dir . '/' . $files);
                                rmdir($dir . '/' . $files);
                            }
                        }
                    }
                }
            }
        }
        
        $dir = 'link/to/your/dir';
        emptyDir($dir);
        rmdir($dir);
        

        【讨论】:

          【解决方案6】:

          我的案例有很多棘手的目录(包含特殊字符、深度嵌套等的名称)和隐藏文件,这些文件在其他建议的解决方案中会产生“目录非空”错误。由于仅 Unix 的解决方案是不可接受的,因此我进行了测试,直到找到以下解决方案(在我的情况下效果很好):

          function removeDirectory($path) {
              // The preg_replace is necessary in order to traverse certain types of folder paths (such as /dir/[[dir2]]/dir3.abc#/)
              // The {,.}* with GLOB_BRACE is necessary to pull all hidden files (have to remove or get "Directory not empty" errors)
              $files = glob(preg_replace('/(\*|\?|\[)/', '[$1]', $path).'/{,.}*', GLOB_BRACE);
              foreach ($files as $file) {
                  if ($file == $path.'/.' || $file == $path.'/..') { continue; } // skip special dir entries
                  is_dir($file) ? removeDirectory($file) : unlink($file);
              }
              rmdir($path);
              return;
          }
          

          【讨论】:

          • 为了扩展对 preg_replace 的需求,这是必要的,因为某些目录(带有特殊字符)会省略明显存在的子目录。我从 glob() 的 php.net 文档中的评论中找到了 preg_replace 注释,其他人在同一问题上挣扎了几个小时。
          • 这也是唯一能解决我问题的+1,谢谢
          【解决方案7】:

          来自http://php.net/manual/en/function.rmdir.php#91797

          Glob 函数不返回隐藏文件,因此 scandir 在尝试递归删除树时可能更有用。

          <?php 
          public static function delTree($dir) { 
             $files = array_diff(scandir($dir), array('.','..')); 
              foreach ($files as $file) { 
                (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); 
              } 
              return rmdir($dir); 
            } 
          ?>
          

          【讨论】:

            【解决方案8】:

            试试以下方便的功能:

            /**
             * Removes directory and its contents
             *
             * @param string $path Path to the directory.
             */
            function _delete_dir($path) {
              if (!is_dir($path)) {
                throw new InvalidArgumentException("$path must be a directory");
              }
              if (substr($path, strlen($path) - 1, 1) != DIRECTORY_SEPARATOR) {
                $path .= DIRECTORY_SEPARATOR;
              }
              $files = glob($path . '*', GLOB_MARK);
              foreach ($files as $file) {
                if (is_dir($file)) {
                  _delete_dir($file);
                } else {
                  unlink($file);
                }
              }
              rmdir($path);
            }
            

            【讨论】:

              【解决方案9】:

              我不是来删除文件夹的,因为 PHP 告诉我它不是空的。但它是。 Naman 的功能是完成我的好解决方案。所以这就是我使用的:

              function emptyDir($dir) {
                  if (is_dir($dir)) {
                      $scn = scandir($dir);
                      foreach ($scn as $files) {
                          if ($files !== '.') {
                              if ($files !== '..') {
                                  if (!is_dir($dir . '/' . $files)) {
                                      unlink($dir . '/' . $files);
                                  } else {
                                      emptyDir($dir . '/' . $files);
                                      rmdir($dir . '/' . $files);
                                  }
                              }
                          }
                      }
                  }
              }
              
              function deleteDir($dir) {
              
                  foreach(glob($dir . '/' . '*') as $file) {
                      if(is_dir($file)){
              
              
                          deleteDir($file);
                      } else {
              
                        unlink($file);
                      }
                  }
                  emptyDir($dir);
                  rmdir($dir);
              }
              

              所以,要删除一个目录并递归地删除它的内容:

              deleteDir($dir);
              

              【讨论】:

                【解决方案10】:

                使用此功能,您将能够删除任何文件或文件夹

                function deleteDir($dirPath)
                {
                    if (!is_dir($dirPath)) {
                        if (file_exists($dirPath) !== false) {
                            unlink($dirPath);
                        }
                        return;
                    }
                
                    if ($dirPath[strlen($dirPath) - 1] != '/') {
                        $dirPath .= '/';
                    }
                
                    $files = glob($dirPath . '*', GLOB_MARK);
                    foreach ($files as $file) {
                        if (is_dir($file)) {
                            deleteDir($file);
                        } else {
                            unlink($file);
                        }
                    }
                
                    rmdir($dirPath);
                }
                

                【讨论】:

                  【解决方案11】:

                  已经有很多解决方案,还有另一种可能,使用 PHP 箭头函数的代码更少:

                  function rrmdir(string $directory): bool
                  {
                      array_map(fn (string $file) => is_dir($file) ? rrmdir($file) : unlink($file), glob($directory . '/' . '*'));
                  
                      return rmdir($directory);
                  }
                  

                  【讨论】:

                    【解决方案12】:
                    function delTree($dir) { 
                        $files = array_diff(scandir($dir), array('.','..')); 
                         foreach ($files as $file) 
                           (is_dir("$dir/$file")) ? delTree("$dir/$file") : @unlink("$dir/$file"); 
                         return @rmdir($dir); 
                    } 
                    

                    【讨论】:

                      猜你喜欢
                      • 2013-08-05
                      • 2012-05-31
                      • 2016-10-16
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-12-06
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多