【问题标题】:Delete directories recursively in Java在Java中递归删除目录
【发布时间】:2010-10-21 05:45:55
【问题描述】:

有没有办法在 Java 中递归删除整个目录?

在正常情况下,可以删除一个空目录。 然而,当涉及到删除包含内容的整个目录时,就不再那么简单了。

如何在 Java 中删除包含内容的整个目录?

【问题讨论】:

  • File.delete() 应该在使用非空目录调用它时简单地返回 false。
  • 如果您使用的是 Java 8,请参阅@RoK 的回答。

标签: java file-io filesystems delete-directory


【解决方案1】:

使用 Java 7,我们终于可以do this with reliable symlink detection.(我不认为 Apache 的 commons-io 目前具有可靠的符号链接检测,因为它不处理在 Windows 上创建的链接mklink.)

为了历史起见,这是 Java 7 之前的答案,遵循符号链接。

void delete(File f) throws IOException {
  if (f.isDirectory()) {
    for (File c : f.listFiles())
      delete(c);
  }
  if (!f.delete())
    throw new FileNotFoundException("Failed to delete file: " + f);
}

【讨论】:

  • File.delete() 没有那个功能。
  • @Erickson:FileNotFoundException 不是删除失败的一个糟糕的例外吗?如果文件确实不再存在,那么它一定已经被删除了,这意味着,从语义上讲,删除并没有失败——它没有任何关系。如果因为其他原因失败,也不是因为找不到文件。
  • 非常小心。这将取消引用符号链接。如果你在例如linux,并有一个文件夹foo 和一个链接foo/link 这样link->/,调用delete(new File(foo)) 将删除你的用户允许的尽可能多的文件系统!!
  • @Miquel 这没有意义——我们为什么要小心?当然,提供的代码的目的是删除整个目录,这就是它看起来要做的事情。我不明白这里有什么危险。
  • @Joehot200 你是对的,在目录符号链接上调用 delete 不会删除目录,只会删除符号链接本身。删除目录实际上需要使用ReadSymbolicLink 明确地遵循符号链接。我的错!很好发现
【解决方案2】:

也许这个问题的解决方案可能是使用来自 erickson 的答案的代码重新实现 File 类的 delete 方法:

public class MyFile extends File {

  ... <- copy constructor

  public boolean delete() {
    if (f.isDirectory()) {
      for (File c : f.listFiles()) {
        return new MyFile(c).delete();
      }
    } else {
        return f.delete();
    }
  }
}

【讨论】:

  • 我认为它的实现是为了模仿大多数命令 shell 实用程序(如“rm”、“rmdir”和“del”)的行为。在这两种选择中,当前的实现肯定会最大程度地减少整体意外(和愤怒)的可能性。它不会改变。
  • 一般来说,我看到的唯一扩展的 Java JRE 包来自 Swing。通常,扩展 java.io.File 等其他类是一个坏主意,因为它有可能导致事情以意想不到的方式发生。
【解决方案3】:

您应该查看Apache's commons-io。它有一个 FileUtils 类,可以做你想做的事。

FileUtils.deleteDirectory(new File("directory"));

【讨论】:

【解决方案4】:

这是一个接受命令行参数的简单主要方法,您可能需要附加自己的错误检查或将其调整为您认为合适的方式。

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class DeleteFiles {

/**
 * @param intitial arguments take in a source to read from and a 
 * destination to read to
 */
    public static void main(String[] args)
                     throws FileNotFoundException,IOException {
        File src = new File(args[0]);
        if (!src.exists() ) {
            System.out.println("FAILURE!");
        }else{
            // Gathers files in directory
            File[] a = src.listFiles();
            for (int i = 0; i < a.length; i++) {
                //Sends files to recursive deletion method
                fileDelete(a[i]);
            }
            // Deletes original source folder
            src.delete();
            System.out.println("Success!");
        }
    }

    /**
     * @param srcFile Source file to examine
     * @throws FileNotFoundException if File not found
     * @throws IOException if File not found
     */
    private static void fileDelete(File srcFile)
                     throws FileNotFoundException, IOException {
        // Checks if file is a directory
        if (srcFile.isDirectory()) {
            //Gathers files in directory
            File[] b = srcFile.listFiles();
            for (int i = 0; i < b.length; i++) {
                //Recursively deletes all files and sub-directories
                fileDelete(b[i]);
            }
            // Deletes original sub-directory file
            srcFile.delete();
        } else {
            srcFile.delete();
        }
    }
}

希望对你有帮助!

【讨论】:

    【解决方案5】:

    GuavaGuava 9 之前支持 Files.deleteRecursively(File)

    来自Guava 10

    已弃用。此方法存在较差的符号链接检测和竞争条件。仅通过对诸如rm -rfdel /s 之类的操作系统命令进行外壳处理,才能适当地支持此功能。 计划在 Guava 11.0 版中从 Guava 中删除此方法。

    因此Guava 11中没有这种方法。

    【讨论】:

    • 太糟糕了。脱壳似乎有点粗糙且不便携。如果 Apache commons 版本运行正常,那么想必也不是不可能实现的。
    • @andrew Apache Commons 实现应该与导致 Guava 删除其实现的问题类似,请参阅code.google.com/p/guava-libraries/issues/detail?id=365
    • apache commons 版本检测符号链接,并且根本不遍历文件的子文件。
    • Guava 21.0 将此添加为 MoreFiles.deleteRecursively()
    【解决方案6】:

    刚刚看到我的解决方案与埃里克森的解决方案或多或少相同,只是打包为静态方法。把它放在某个地方,它比安装所有 Apache Commons (如您所见)非常简单的东西要轻得多。

    public class FileUtils {
        /**
         * By default File#delete fails for non-empty directories, it works like "rm". 
         * We need something a little more brutual - this does the equivalent of "rm -r"
         * @param path Root File Path
         * @return true iff the file and all sub files/directories have been removed
         * @throws FileNotFoundException
         */
        public static boolean deleteRecursive(File path) throws FileNotFoundException{
            if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
            boolean ret = true;
            if (path.isDirectory()){
                for (File f : path.listFiles()){
                    ret = ret && deleteRecursive(f);
                }
            }
            return ret && path.delete();
        }
    }
    

    【讨论】:

      【解决方案7】:

      符号链接和上述代码失败的两种方式......并且不知道解决方案。

      方式#1

      运行这个来创建一个测试:

      echo test > testfile
      mkdir dirtodelete
      ln -s badlink dirtodelete/badlinktodelete
      

      在这里你可以看到你的测试文件和测试目录:

      $ ls testfile dirtodelete
      testfile
      
      dirtodelete:
      linktodelete

      然后运行你的 commons-io deleteDirectory()。它崩溃说找不到文件。不确定其他示例在这里做了什么。 Linux rm 命令会简单地删除链接,并且目录上的 rm -r 也会。

      Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete

      方式#2

      运行这个来创建一个测试:

      mkdir testdir
      echo test > testdir/testfile
      mkdir dirtodelete
      ln -s ../testdir dirtodelete/dirlinktodelete
      

      在这里你可以看到你的测试文件和测试目录:

      $ ls dirtodelete testdir
      dirtodelete:
      dirlinktodelete
      
      testdir:
      testfile
      

      然后运行您的 commons-io deleteDirectory() 或人们发布的示例代码。它不仅会删除目录,还会删除被删除目录之外的测试文件。 (它隐式地取消引用目录,并删除内容)。 rm -r 只会删除链接。您需要使用类似这样的方法删除取消引用的文件:“find -L ditodelete -t​​ype f -exec rm {} \;”。

      $ ls dirtodelete testdir
      ls: cannot access dirtodelete: No such file or directory
      testdir:

      【讨论】:

        【解决方案8】:
        public void deleteRecursive(File path){
            File[] c = path.listFiles();
            System.out.println("Cleaning out folder:" + path.toString());
            for (File file : c){
                if (file.isDirectory()){
                    System.out.println("Deleting file:" + file.toString());
                    deleteRecursive(file);
                    file.delete();
                } else {
                    file.delete();
                }
            }
            path.delete();
        }
        

        【讨论】:

        【解决方案9】:
        public static void deleteDirectory(File path) 
        {
            if (path == null)
                return;
            if (path.exists())
            {
                for(File f : path.listFiles())
                {
                    if(f.isDirectory()) 
                    {
                        deleteDirectory(f);
                        f.delete();
                    }
                    else
                    {
                        f.delete();
                    }
                }
                path.delete();
            }
        }
        

        【讨论】:

        • 不错的代码,但有一个错误,修复后,它可以工作。 deleteDirectory(f) 下的 f.delete() 行将抛出 NoSuchFileException,因为 deleteDirectory(f) 已经删除了该文件。每个目录在传入deleteDirectory(f) 并被path.delete() 删除时都会成为路径。因此,我们在if f.isDerectory 部分不需要f.delete()。因此,只需删除 deleteDirectory(f) 下的 f.delete(); 即可。
        【解决方案10】:

        Java 7 添加了对带有符号链接处理的遍历目录的支持:

        import java.nio.file.*;
        
        public static void removeRecursive(Path path) throws IOException
        {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>()
            {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException
                {
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }
        
                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
                {
                    // try to delete the file anyway, even if its attributes
                    // could not be read, since delete-only access is
                    // theoretically possible
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }
        
                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
                {
                    if (exc == null)
                    {
                        Files.delete(dir);
                        return FileVisitResult.CONTINUE;
                    }
                    else
                    {
                        // directory iteration failed; propagate exception
                        throw exc;
                    }
                }
            });
        }
        

        我将其用作平台特定方法的后备方法(在此未经测试代码中):

        public static void removeDirectory(Path directory) throws IOException
        {
            // does nothing if non-existent
            if (Files.exists(directory))
            {
                try
                {
                    // prefer OS-dependent directory removal tool
                    if (SystemUtils.IS_OS_WINDOWS)
                        Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
                    else if (SystemUtils.IS_OS_UNIX)
                        Processes.execute("/bin/rm", "-rf", directory.toString());
                }
                catch (ProcessExecutionException | InterruptedException e)
                {
                    // fallback to internal implementation on error
                }
        
                if (Files.exists(directory))
                    removeRecursive(directory);
            }
        }
        

        (SystemUtils 来自Apache Commons Lang。进程是私有的,但它的行为应该是显而易见的。)

        【讨论】:

        • 我确实发现了 Files.walkFileTree 的一个问题 - 它不足以实现一种递归删除版本,在该版本中你一直删除文件直到你用完选项。它对于快速失败的版本来说已经足够了,但快速失败并不总是你想要的(例如,如果你正在清理临时文件,你想要立即删除,而不是快速失败。)
        • 我不明白为什么这是真的。你可以随心所欲地处理错误——你不需要快速失败。我可以预见的唯一问题是它可能无法处理在当前目录遍历期间创建的新文件,但这是一种更适合自定义解决方案的独特情况。
        • 如果您抑制来自 visitFile 的错误并在单个文件上调用 walkFileTree 失败,您不会收到任何错误(因此 visitFile 必须 传播发生的任何错误。)如果您重新删除一个目录并且删除一个文件失败,唯一调用的回调是 postVisitDirectory。即,如果您在访问一个文件时遇到错误,它不会访问目录中的其他文件。这就是我的意思。我确信可能有一些方法可以解决这个问题,但到现在为止,我们已经编写了比传统递归删除例程更多的代码,因此我们决定不使用它。
        • 感谢您的第一个代码,它对我很有用,但我不得不更改它,因为它没有完成简单的 deltree:我不得不忽略“postVisitDirectory”中的异常并返回 CONTINUE 无论如何因为无法完全删除以下简单树:一个目录,其中有另一个目录,其中一个文件。在 Windows 上,所有这些都非常简单/正常。
        • 这一切都是从我得到的 java.nio.file.DirectoryNotEmptyException 开始的。我发现了使用 visitFileFailed 的情况。如果您的目录结构在 windows 中有一个 junction 类型的链接。这可能会导致您出现 2 个问题: *) Files.walkFileTree 跟随链接进入交汇点并删除那里的所有内容。 *) 如果连接目标目录已被删除,则通过 Files.walkFileTree 解析链接将失败,并在 visitFileFailed 中捕获 NoSuchFileException。
        【解决方案11】:

        一个有栈但没有递归方法的解决方案:

        File dir = new File("/path/to/dir");
        File[] currList;
        Stack<File> stack = new Stack<File>();
        stack.push(dir);
        while (! stack.isEmpty()) {
            if (stack.lastElement().isDirectory()) {
                currList = stack.lastElement().listFiles();
                if (currList.length > 0) {
                    for (File curr: currList) {
                        stack.push(curr);
                    }
                } else {
                    stack.pop().delete();
                }
            } else {
                stack.pop().delete();
            }
        }
        

        【讨论】:

        • +1 用于使用堆栈。这将适用于包含深层嵌套子目录的目录,而其他基于堆栈的方法将失败。
        • 看到嵌套几百个方法调用通常没有问题,我认为您可能会更早地遇到文件系统限制。
        • 注意java.io.File 类的list* 方法。来自 Javadocs:“如果此抽象路径名不表示目录,或者发生 I/O 错误,则返回 null。”所以:if (currList.length &gt; 0) { 变为 if (null != currList &amp;&amp; currList.length &gt; 0) {
        • 我使用 ArrayDeque 而不是 Stack 稍快一些。 (不同步)
        【解决方案12】:

        你可以使用:

        org.apache.commons.io.FileUtils.deleteQuietly(destFile);

        删除文件,从不抛出异常。如果文件是一个目录,删除它和所有子目录。 File.delete() 和这个方法的区别是: 要删除的目录不必为空。 无法删除文件或目录时不会抛出异常。

        【讨论】:

          【解决方案13】:
          for(Path p : Files.walk(directoryToDelete).
                  sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
                  toArray(Path[]::new))
          {
              Files.delete(p);
          }
          

          或者如果你想处理IOException:

          Files.walk(directoryToDelete).
              sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
              forEach(p -> {
                  try { Files.delete(p); }
                  catch(IOException e) { /* ... */ }
                });
          

          【讨论】:

          • 这帮助我想出了一个 Scala 版本:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
          • 排序真的有必要吗? walk 方法已经保证了深度优先遍历。
          • 比较器可以从 Collections.reverseOrder() 回收,因此假设它已被静态导入,您的代码将是 for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))
          • @namero999 你的意思是Comparator.reverseOrderFiles.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
          • @Jeff 很确定你是对的,主要是凭记忆去的 :)
          【解决方案14】:

          在 Java 7+ 中,您可以使用 Files 类。代码很简单:

          Path directory = Paths.get("/tmp");
          Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
             @Override
             public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                 Files.delete(file);
                 return FileVisitResult.CONTINUE;
             }
          
             @Override
             public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                 Files.delete(dir);
                 return FileVisitResult.CONTINUE;
             }
          });
          

          【讨论】:

          • 这个方案看起来很优雅,根本不包含目录遍历逻辑!
          • “去海底深处寻找一颗珍珠。”。这是迄今为止我找到的最简洁的解决方案。不得不深潜才能找到它。太棒了!
          • “代码不是”简单地删除一个目录“非常简单” :-) 但是,我认为这是纯 java 中最好的解决方案。
          • 请注意此处使用的 walkFileTree 重载“不遵循符号链接”。 (Javadoc:docs.oracle.com/javase/7/docs/api/java/nio/file/…
          【解决方案15】:

          如果你有Spring,可以使用FileSystemUtils.deleteRecursively

          import org.springframework.util.FileSystemUtils;
          
          boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
          

          【讨论】:

            【解决方案16】:

            虽然使用 file.delete() 可以轻松删除文件,但删除目录必须为空。使用递归很容易做到这一点。例如:

            public static void clearFolders(String[] args) {
                    for(String st : args){
                        File folder = new File(st);
                        if (folder.isDirectory()) {
                            File[] files = folder.listFiles();
                            if(files!=null) { 
                                for(File f: files) {
                                    if (f.isDirectory()){
                                        clearFolders(new String[]{f.getAbsolutePath()});
                                        f.delete();
                                    } else {
                                        f.delete();
                                    }
                                }
                            }
                        }
                    }
                }
            

            【讨论】:

              【解决方案17】:

              没有 Commons IO 和

              public static void deleteRecursive(File path){
                          path.listFiles(new FileFilter() {
                              @Override
                              public boolean accept(File pathname) {
                                  if (pathname.isDirectory()) {
                                      pathname.listFiles(this);
                                      pathname.delete();
                                  } else {
                                      pathname.delete();
                                  }
                                  return false;
                              }
                          });
                          path.delete();
                      }
              

              【讨论】:

                【解决方案18】:

                在遗留项目中,我需要创建本机 Java 代码。我创建此代码类似于 Paulitex 代码。看到:

                public class FileHelper {
                
                   public static boolean delete(File fileOrFolder) {
                      boolean result = true;
                      if(fileOrFolder.isDirectory()) {
                         for (File file : fileOrFolder.listFiles()) {
                            result = result && delete(file);
                         }
                      }
                      result = result && fileOrFolder.delete();
                      return result;
                   } 
                }
                

                还有单元测试:

                public class FileHelperTest {
                
                    @Before
                    public void setup() throws IOException {
                       new File("FOLDER_TO_DELETE/SUBFOLDER").mkdirs();
                       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO").mkdirs();
                       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO/TEST_FILE.txt").createNewFile();
                    }
                
                    @Test
                    public void deleteFolderWithFiles() {
                       File folderToDelete = new File("FOLDER_TO_DELETE");
                       Assert.assertTrue(FileHelper.delete(folderToDelete));
                       Assert.assertFalse(new File("FOLDER_TO_DELETE").exists());
                    }
                
                }
                

                【讨论】:

                  【解决方案19】:

                  单线解决方案(Java8)递归删除所有文件和目录,包括起始目录:

                  Files.walk(Paths.get("c:/dir_to_delete/"))
                                  .map(Path::toFile)
                                  .sorted((o1, o2) -> -o1.compareTo(o2))
                                  .forEach(File::delete);
                  

                  我们使用比较器来反转顺序,否则 File::delete 将无法删除可能非空的目录。因此,如果您想保留目录并仅删除文件,只需删除 sorted() 中的比较器 完全删除排序并添加文件过滤器:

                  Files.walk(Paths.get("c:/dir_to_delete/"))
                                  .filter(Files::isRegularFile)
                                  .map(Path::toFile)
                                  .forEach(File::delete);
                  

                  【讨论】:

                  • 您需要将第一个中的排序更改为.sorted(Comparator::reverseOrder),以删除所有目录。否则父目录排在子目录之前,因此不会删除,因为它不是空的。对于那些使用 Java 8 的人来说,这是一个很好的答案!
                  • 正确的方法是.sorted(Comparator.reverseOrder()) 建议Comparator::reverseOrder 确实 工作。见:stackoverflow.com/questions/43036611/…
                  • Robin,注意“-o1.compareTo(o2)”中的减号。和 .sorted(Comparator.reverseOrder) 一样
                  • Files.walk 是连续的吗?或者这个答案是否需要 forEachOrdered 而不是 forEach 以避免尝试删除非空目录?
                  • 这个答案有问题:walk() 返回的流应该被关闭,因为它“包含对一个或多个打开目录的引用”(Javadoc)。
                  【解决方案20】:

                  我编写了这个具有 3 个安全标准的例程,以便更安全地使用。

                  package ch.ethz.idsc.queuey.util;
                  
                  import java.io.File;
                  import java.io.IOException;
                  
                  /** recursive file/directory deletion
                   * 
                   * safety from erroneous use is enhanced by three criteria
                   * 1) checking the depth of the directory tree T to be deleted
                   * against a permitted upper bound "max_depth"
                   * 2) checking the number of files to be deleted #F
                   * against a permitted upper bound "max_count"
                   * 3) if deletion of a file or directory fails, the process aborts */
                  public final class FileDelete {
                      /** Example: The command
                       * FileDelete.of(new File("/user/name/myapp/recordings/log20171024"), 2, 1000);
                       * deletes given directory with sub directories of depth of at most 2,
                       * and max number of total files less than 1000. No files are deleted
                       * if directory tree exceeds 2, or total of files exceed 1000.
                       * 
                       * abort criteria are described at top of class
                       * 
                       * @param file
                       * @param max_depth
                       * @param max_count
                       * @return
                       * @throws Exception if criteria are not met */
                      public static FileDelete of(File file, int max_depth, int max_count) throws IOException {
                          return new FileDelete(file, max_depth, max_count);
                      }
                  
                      // ---
                      private final File root;
                      private final int max_depth;
                      private int removed = 0;
                  
                      /** @param root file or a directory. If root is a file, the file will be deleted.
                       *            If root is a directory, the directory tree will be deleted.
                       * @param max_depth of directory visitor
                       * @param max_count of files to delete
                       * @throws IOException */
                      private FileDelete(final File root, final int max_depth, final int max_count) throws IOException {
                          this.root = root;
                          this.max_depth = max_depth;
                          // ---
                          final int count = visitRecursively(root, 0, false);
                          if (count <= max_count) // abort criteria 2)
                              visitRecursively(root, 0, true);
                          else
                              throw new IOException("more files to be deleted than allowed (" + max_count + "<=" + count + ") in " + root);
                      }
                  
                      private int visitRecursively(final File file, final int depth, final boolean delete) throws IOException {
                          if (max_depth < depth) // enforce depth limit, abort criteria 1)
                              throw new IOException("directory tree exceeds permitted depth");
                          // ---
                          int count = 0;
                          if (file.isDirectory()) // if file is a directory, recur
                              for (File entry : file.listFiles())
                                  count += visitRecursively(entry, depth + 1, delete);
                          ++count; // count file as visited
                          if (delete) {
                              final boolean deleted = file.delete();
                              if (!deleted) // abort criteria 3)
                                  throw new IOException("cannot delete " + file.getAbsolutePath());
                              ++removed;
                          }
                          return count;
                      }
                  
                      public int deletedCount() {
                          return removed;
                      }
                  
                      public void printNotification() {
                          int count = deletedCount();
                          if (0 < count)
                              System.out.println("deleted " + count + " file(s) in " + root);
                      }
                  }
                  

                  【讨论】:

                    【解决方案21】:

                    好吧,让我们假设一个例子,

                    import java.io.File;
                    import java.io.IOException;
                    
                    public class DeleteDirectory
                    {
                       private static final String folder = "D:/project/java";
                     
                       public static void main(String[] args) throws IOException
                       {
                          File fl = new File(folder);
                          if(!fl.exists()) // checking if directory exists
                          {
                             System.out.println("Sorry!! directory doesn't exist.");
                          }
                          else
                          {
                             DeleteDirectory dd = new DeleteDirectory();
                             dd.deleteDirectory(fl);
                          }
                       }
                     
                       public void deleteDirectory(File file) throws IOException
                       {
                          if(file.isDirectory())
                          {
                             if(file.list().length == 0)
                             { 
                                deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
                             }
                             else
                             {
                                File fe[] = file.listFiles();
                                for(File deleteFile : fe)
                                {
                                   deleteDirectory(deleteFile); // recursive call
                                }
                                if(file.list().length == 0)
                                {
                                   deleteEmptyDirectory(file);
                                }
                             }
                          }
                          else
                          {
                             file.delete();
                             System.out.println("File deleted : " + file.getAbsolutePath());
                          }
                       }
                     
                       private void deleteEmptyDirectory(File fi)
                       {
                          fi.delete();
                          System.out.println("Directory deleted : " + fi.getAbsolutePath());
                       }
                    }
                    

                    有关更多信息,请参阅以下资源

                    Delete directory

                    【讨论】:

                      【解决方案22】:

                      处理异常的最佳解决方案与从方法引发的异常应始终描述该方法尝试(和失败)执行的方法一致:

                      private void deleteRecursive(File f) throws Exception {
                          try {
                              if (f.isDirectory()) {
                                  for (File c : f.listFiles()) {
                                      deleteRecursive(c);
                                  }
                              }
                              if (!f.delete()) {
                                  throw new Exception("Delete command returned false for file: " + f);
                              }
                          } 
                          catch (Exception e) {
                              throw new Exception("Failed to delete the folder: " + f, e);
                          }
                      }
                      

                      【讨论】:

                        【解决方案23】:

                        以下代码递归删除给定文件夹中的所有内容。

                        boolean deleteDirectory(File directoryToBeDeleted) {
                            File[] allContents = directoryToBeDeleted.listFiles();
                            if (allContents != null) {
                                for (File file : allContents) {
                                    deleteDirectory(file);
                                }
                            }
                            return directoryToBeDeleted.delete();
                        }
                        

                        【讨论】:

                          【解决方案24】:

                          rm -rfFileUtils.deleteDirectory 性能很多

                          经过广泛的基准测试,我们发现使用rm -rf 比使用FileUtils.deleteDirectory 快​​几倍。

                          当然,如果您有一个小目录或简单目录,那没关系,但在我们的例子中,我们有多个千兆字节和深度嵌套的子目录,FileUtils.deleteDirectory 需要 10 多分钟,@ 只需 1 分钟987654326@.

                          这是我们的粗略 Java 实现:

                          // Delete directory given and all subdirectories and files (i.e. recursively).
                          //
                          static public boolean deleteDirectory( File file ) throws IOException, InterruptedException {
                          
                              if ( file.exists() ) {
                          
                                  String deleteCommand = "rm -rf " + file.getAbsolutePath();
                                  Runtime runtime = Runtime.getRuntime();
                          
                                  Process process = runtime.exec( deleteCommand );
                                  process.waitFor();
                          
                                  return true;
                              }
                          
                              return false;
                          
                          }
                          

                          如果您要处理大型或复杂的目录,值得一试。

                          【讨论】:

                          • @cricket_007 哪些平台?
                          • Windows?开放式? BSD?
                          • @cricket_007 绝对不是 Windows。这是在 Android 和 macOS 上测试和使用的。
                          【解决方案25】:

                          Guava 提供单行:MoreFiles.deleteRecursively()

                          与许多共享的示例不同,它考虑了符号链接,并且不会(默认情况下)删除提供的路径之外的文件。

                          【讨论】:

                            【解决方案26】:

                            // 带有 lambda 和流的 Java 8,如果参数是目录

                            static boolean delRecursive(File dir) {
                                return Arrays.stream(dir.listFiles()).allMatch((f) -> f.isDirectory() ? delRecursive(f) : f.delete()) && dir.delete();
                            }
                            

                            //如果参数是文件或目录

                            static boolean delRecursive(File fileOrDir) {
                                return fileOrDir.isDirectory() ? Arrays.stream(fileOrDir.listFiles()).allMatch((f) -> delRecursive(f)) && fileOrDir.delete() : fileOrDir.delete();
                            }
                            

                            【讨论】:

                              【解决方案27】:

                              Guava 21.0 及更高版本

                              自 Guava 21.0 以来,MoreFiles 类的 void deleteRecursively(Path path, RecursiveDeleteOption... options) throws IOException 静态方法可用。

                              请看Javadoc documentation:

                              public static void deleteRecursively(Path 路径, RecursiveDeleteOption... 选项) 抛出IOException

                              递归删除给定path 处的文件或目录。删除符号链接,而不是它们的目标(受以下警告)。

                              如果在尝试读取、打开或删除给定目录下的任何文件时发生 I/O 异常,则此方法会跳过该文件并继续。收集所有此类异常,并在尝试删除所有文件后,抛出 IOException 包含这些异常为 suppressed exceptions

                              【讨论】:

                                猜你喜欢
                                • 2014-05-12
                                • 2018-10-15
                                • 2016-04-18
                                • 1970-01-01
                                • 2017-01-09
                                相关资源
                                最近更新 更多