在Java中递归删除目录

437

在Java中有没有一种递归删除整个目录的方法?

通常情况下,可以删除空目录。但是当需要删除带有内容的整个目录时,就不那么简单了。

你如何在Java中删除带有内容的整个目录?


4
如果使用非空目录调用File.delete()方法,应该简单地返回false。 - Ben S
如果您正在使用Java 8,请查看@RoK的答案。 - Robin
26个回答

1

Guava 21.0及更高版本

自Guava 21.0版本以后,MoreFiles类提供了void deleteRecursively(Path path, RecursiveDeleteOption... options) throws IOException静态方法。

请参阅Javadoc文档

public static void deleteRecursively(Path path, RecursiveDeleteOption... options) throws IOException

递归删除给定路径下的文件或目录。会删除符号链接,但不会删除其目标(以下有例外情况)。

如果在尝试读取、打开或删除给定目录下的任何文件时发生I/O异常,则此方法将跳过该文件并继续执行。所有这些异常都将被收集起来,在尝试删除所有文件后,将抛出一个包含这些异常作为抑制异常IOException


1
没有Commons IO和Java SE 7以下版本。
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();
        }

1
// 如果参数是目录,使用Java 8的lambda和stream
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();
}

1

rm -rfFileUtils.deleteDirectory 更高效。

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

当然,如果您有一个小型或简单的目录,这并不重要,但在我们的情况下,我们有多个千兆字节和深度嵌套的子目录,使用 FileUtils.deleteDirectory 需要超过10分钟,而使用 rm -rf 只需要1分钟。

以下是我们粗略的 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 是哪些平台? - Joshua Pinter
Windows?OpenWrt?BSD? - OneCricketeer
2
@cricket_007 绝对不是Windows。这已经在Android和macOS上进行了测试和使用。 - Joshua Pinter
代码在文件名中包含空格时会失败。我宁愿等待10分钟 :-) - David L.
@DavidL。有趣。我们从未遇到过这种情况。您是指目录名称中带有空格还是路径中任何位置都有空格?还是两者都有? - Joshua Pinter
显示剩余2条评论

0
我编写了这个程序例程,其中包含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);
    }
}

0

虽然可以使用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();
                        }
                    }
                }
            }
        }
    }

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