Java中递归删除目录

发布于 2024-07-17 03:05:50 字数 121 浏览 12 评论 0原文

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

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

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

Is there a way to delete entire directories recursively in Java?

In the normal case it is possible to delete an empty directory.
However when it comes to deleting entire directories with contents, it is not that simple anymore.

How do you delete entire directories with contents in Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(26

牵你的手,一向走下去 2024-07-24 03:05:50

您应该查看 Apache 的 commons-io。 它有一个 FileUtils 类将执行您想要的操作。

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

You should check out Apache's commons-io. It has a FileUtils class that will do what you want.

FileUtils.deleteDirectory(new File("directory"));
烟凡古楼 2024-07-24 03:05:50

有了 Java 7,我们终于可以通过可靠的符号链接检测来做到这一点。(我不认为 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);
}

With Java 7, we can finally do this with reliable symlink detection. (I don't consider Apache's commons-io to have reliable symlink detection at this time, as it doesn't handle links on Windows created with mklink.)

For the sake of history, here's a pre-Java 7 answer, which follows symlinks.

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);
}
月朦胧 2024-07-24 03:05:50

在 Java 7+ 中,您可以使用 Files< /a> 类。 代码非常简单:

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

In Java 7+ you can use Files class. Code is very simple:

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;
   }
});
执笔绘流年 2024-07-24 03:05:50

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

try (var dirStream = Files.walk(Paths.get("c:/dir_to_delete/"))) {
    dirStream
        .map(Path::toFile)
        .sorted(Comparator.reverseOrder())
        .forEach(File::delete);
}

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

try (var dirStream = Files.walk(Paths.get("c:/dir_to_delete/"))) {
    dirStream
        .filter(Files::isRegularFile)
        .map(Path::toFile)
        .forEach(File::delete);
}

One-liner solution (Java8) to delete all files and directories recursively including starting directory:

try (var dirStream = Files.walk(Paths.get("c:/dir_to_delete/"))) {
    dirStream
        .map(Path::toFile)
        .sorted(Comparator.reverseOrder())
        .forEach(File::delete);
}

We use a comparator for reversed order, otherwise File::delete won't be able to delete possibly non-empty directory. So, if you want to keep directories and only delete files just remove the comparator in sorted() or remove sorting completely and add files filter:

try (var dirStream = Files.walk(Paths.get("c:/dir_to_delete/"))) {
    dirStream
        .filter(Files::isRegularFile)
        .map(Path::toFile)
        .forEach(File::delete);
}
往昔成烟 2024-07-24 03:05:50

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。进程是私有的,但其行为应该是显而易见的。)

Java 7 added support for walking directories with symlink handling:

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

I use this as a fallback from platform-specific methods (in this untested code):

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 is from Apache Commons Lang. Processes is private but its behavior should be obvious.)

巡山小妖精 2024-07-24 03:05:50

刚刚看到我的解决方案与埃里克森的解决方案或多或少相同,只是打包为静态方法。 把它放在某个地方,它比安装所有 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();
    }
}

Just saw my solution is more or less the same as erickson's, just packaged as a static method. Drop this somewhere, it's much lighter weight than installing all of Apache Commons for something that (as you can see) is quite simple.

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();
    }
}
夏天碎花小短裙 2024-07-24 03:05:50

使用堆栈且不使用递归方法的解决方案:

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

A solution with a stack and without recursive methods:

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();
    }
}
橙味迷妹 2024-07-24 03:05:50

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

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));

If you have Spring, you can use FileSystemUtils.deleteRecursively:

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
清眉祭 2024-07-24 03:05:50

GuavaFiles.deleteRecursively(File) 支持直至番石榴 9

来自 番石榴 10

已弃用。此方法存在不良的符号链接检测和竞争条件问题。 仅通过 shell 到操作系统命令(例如 rm -rfdel /s)才能适当支持此功能。 计划在 Guava 11.0 版本中从 Guava 中删除该方法。

因此,番石榴 11

Guava had Files.deleteRecursively(File) supported until Guava 9.

From Guava 10:

Deprecated. This method suffers from poor symlink detection and race conditions. This functionality can be supported suitably only by shelling out to an operating system command such as rm -rf or del /s. This method is scheduled to be removed from Guava in Guava release 11.0.

Therefore, there is no such method in Guava 11.

℡Ms空城旧梦 2024-07-24 03:05:50
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) { /* ... */ }
      });
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

Or if you want to handle the IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
吻安 2024-07-24 03:05:50
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();
}
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();
}
生来就爱笑 2024-07-24 03:05:50
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();
    }
}
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();
    }
}
小姐丶请自重 2024-07-24 03:05:50

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

方法#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 dirtydelete -t​​ype f -exec rm {} \;”。

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

Two ways to fail with symlinks and the above code... and don't know the solution.

Way #1

Run this to create a test:

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

Here you see your test file and test directory:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Then run your commons-io deleteDirectory(). It crashes saying the file is not found. Not sure what the other examples do here. The Linux rm command would simply delete the link, and rm -r on the directory would also.

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

Way #2

Run this to create a test:

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

Here you see your test file and test directory:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Then run your commons-io deleteDirectory() or the example code people posted. It deletes not only the directory, but your testfile which is outside the directory being deleted. (It dereferences the directory implicitly, and deletes the contents). rm -r would delete the link only. You need to use something like this delete the dereferenced files: "find -L dirtodelete -type f -exec rm {} \;".

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:
Spring初心 2024-07-24 03:05:50

您可以使用:

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

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

You could use:

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

Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories.
The difference between File.delete() and this method are:
A directory to be deleted does not have to be empty.
No exceptions are thrown when a file or directory cannot be deleted.

摇划花蜜的午后 2024-07-24 03:05:50

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

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

An optimal solution that handles exception consistently with the approach that an exception thrown from a method should always describe what that method was trying (and failed) to do:

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);
    }
}
半葬歌 2024-07-24 03:05:50

在遗留项目中,我需要创建本机 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());
    }

}

In legacy projects, I need to create native Java code. I create this code similar to Paulitex code. See that:

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

And the unit test:

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

}
君勿笑 2024-07-24 03:05:50

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

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

Below code recursively delete all contents in a given folder.

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}
摇划花蜜的午后 2024-07-24 03:05:50

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

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

我希望这有帮助!

Here is a bare bones main method that accepts a command line argument, you may need to append your own error checking or mold it to how you see fit.

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

I hope that helps!

╰◇生如夏花灿烂 2024-07-24 03:05:50

Guava 提供了一句:MoreFiles。递归地删除()

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

Guava provides a one-liner: MoreFiles.deleteRecursively().

Unlike many of the examples shared, it accounts for symbolic links and will not (by default) delete files outside the provided path.

若沐 2024-07-24 03:05:50

也许这个问题的解决方案可能是使用埃里克森答案中的代码重新实现 File 类的删除方法:

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

Maybe a solution for this problem might be to reimplement the delete method of the File class using the code from erickson's answer:

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();
    }
  }
}
小姐丶请自重 2024-07-24 03:05:50

没有 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();
        }

Without Commons IO and < 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();
        }
久随 2024-07-24 03:05:50

// Java 8 与 lambda & 流,如果参数是目录

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

// Java 8 with lambda & stream, if param is directory

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

// if param is file or directory

static boolean delRecursive(File fileOrDir) {
    return fileOrDir.isDirectory() ? Arrays.stream(fileOrDir.listFiles()).allMatch((f) -> delRecursive(f)) && fileOrDir.delete() : fileOrDir.delete();
}
狼亦尘 2024-07-24 03:05:50

Guava 21.0 及更高

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

请参阅 Javadoc 文档

公共静态 无效 递归删除(路径 路径,
RecursiveDeleteOption...选项)
抛出 IOException

递归删除给定路径处的文件或目录。 删除符号链接,而不是其目标(遵循下面的警告)。

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

Guava 21.0 and later

There is the void deleteRecursively(Path path, RecursiveDeleteOption... options) throws IOException static method of the MoreFiles class available since Guava 21.0.

Please, see the Javadoc documentation:

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

Deletes the file or directory at the given path recursively. Deletes symbolic links, not their targets (subject to the caveat below).

If an I/O exception occurs attempting to read, open or delete any file under the given directory, this method skips that file and continues. All such exceptions are collected and, after attempting to delete all files, an IOException is thrown containing those exceptions as suppressed exceptions.

雾里花 2024-07-24 03:05:50

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

如果您正在处理大型或复杂的目录,值得尝试。

rm -rf was much more performant than FileUtils.deleteDirectory.

After extensive benchmarking, we found that using rm -rf was multiple times faster than using FileUtils.deleteDirectory.

Of course, if you have a small or simple directory, it won't matter but in our case we had multiple gigabytes and deeply nested sub directories where it would take over 10 minutes with FileUtils.deleteDirectory and only 1 minute with rm -rf.

Here's our rough Java implementation to do that:

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

Worth trying if you're dealing with large or complex directories.

北陌 2024-07-24 03:05:50

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

While files can easily be deleted using file.delete(), directories are required to be empty to be deleted. Use recursion to do this easily. For example:

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();
                        }
                    }
                }
            }
        }
    }
瑾夏年华 2024-07-24 03:05:50

我编写了这个例程,它具有 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);
    }
}

i coded this routine that has 3 safety criteria for safer use.

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文