在Java中有没有一种递归删除整个目录的方法?
通常情况下,可以删除空目录。但是当需要删除带有内容的整个目录时,就不那么简单了。
你如何在Java中删除带有内容的整个目录?
在Java中有没有一种递归删除整个目录的方法?
通常情况下,可以删除空目录。但是当需要删除带有内容的整个目录时,就不那么简单了。
你如何在Java中删除带有内容的整个目录?
自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
。
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();
}
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();
}
rm -rf
比 FileUtils.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;
}
如果你正在处理大型或复杂的目录,那么值得一试。
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);
}
}
虽然可以使用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();
}
}
}
}
}
}