删除目录中的所有文件(但不删除目录)- 一行解决方案

256

我想删除ABC目录内的所有文件。

当我尝试使用 FileUtils.deleteDirectory(new File("C:/test/ABC/")); 时,它也会删除ABC文件夹。

有没有一行代码的解决方案可以只删除目录内的文件,而不删除目录本身?


2
这是因为.deleteDirectory(甚至名称都暗示着它)用于删除目录。如果文件不是目录,它将获取它所在的目录。 - user1534664
尝试查找FileUtils类中删除文件而不是目录的其他函数。 - user1534664
1
http://www.javacodeexamples.com/java-delete-file-example/ - user1534664
1
你为什么特别需要一行代码呢?性能不能是标准,因为任何第三方库方法都只会递归执行。所以它会给你相同的性能? - Rohit Jain
1
你可以做的一件事是删除目录,然后重新创建它。我们发现使用 rm -rf directory; mkdir directory 比使用 FileUtils.cleanDirectory 更快。 - Joshua Pinter
12个回答

440

56
不错,为了避免人们需要查找,这里是导入语句:import org.apache.commons.io.FileUtils; - Paul Gregoire
5
我需要查找为什么无法找到这个导入内容。原因是你必须从apache.org下载它。下载链接为:http://commons.apache.org/proper/commons-io/download_io.cgi。 - Tomáš Zato
漂亮的解决方案。通过Gradle检查此库:compile "commons-io:commons-io:+" - Leo Nguyen
1
Gradle 依赖 - 编译组:'commons-io',名称:'commons-io',版本:'2.5'。 - Jaydev
1
注意,我们发现调用 rm -rf directory 比使用 FileUtils.cleanDirectory 更有效率。 - Joshua Pinter
显示剩余2条评论

308

你的意思是这样吗?

for(File file: dir.listFiles()) 
    if (!file.isDirectory()) 
        file.delete();

这将仅删除文件,而不是目录。


78
这绝对是更好的答案,因为它不使用外部库! - AlexWien
12
即使如此,如果存在标准方法,就绝对没有理由使用另一个完成相同任务的外部方法。有一天他可能想要摆脱这个库,或者这个库不再得到支持,或者由于许可证原因无法使用该库等等。(这些可能不适用于特定的库,但适用于许多其他库) - AlexWien
12
如果“dir”根目录下有子目录,这将无法删除所有内容。 - Bitcoin Cash - ADA enthusiast
2
@TiagoT 是的,这不会删除非空的子目录。 - Peter Lawrey
5
for(File file: dir.listFiles()) 可能是指... for (File file : new java.io.File("C:\\DeleteMeFolder").listFiles()) ... - Hartmut Pfarr
显示剩余7条评论

72

Peter Lawrey的回答非常好,因为它简单且不依赖于任何特殊条件,这也是你应该这样做的方式。如果你需要删除子目录及其内容,可以使用递归:

void purgeDirectory(File dir) {
    for (File file: dir.listFiles()) {
        if (file.isDirectory())
            purgeDirectory(file);
        file.delete();
    }
}

为了避免影响子目录及其内容(你问题的一部分),请按照以下方式进行修改:

void purgeDirectoryButKeepSubDirectories(File dir) {
    for (File file: dir.listFiles()) {
        if (!file.isDirectory())
            file.delete();
    }
}

或者,既然您想要一行解决方案:

for (File file: dir.listFiles())
    if (!file.isDirectory())
        file.delete();

如果你只是为了简单的任务而使用外部库,那么这不是一个好主意。除非你需要此库来做别的事情,否则最好使用现有的代码。看起来你已经在使用Apache库,所以可以使用它的FileUtils.cleanDirectory()方法。


1
另一方面,如果没有人首先使用外部库,那么其他人就不太可能期望在该外部库中找到类似的行为,也不太可能在那里寻找...我们难道没有足够的“非此即彼”吗?如果库是内聚的并且易于添加到我的项目中,那么我几乎总是更喜欢添加该库。 - J. B. Rainsberger

50

Java 8流式处理

这仅会从ABC中删除文件(子目录不变):

Arrays.stream(new File("C:/test/ABC/").listFiles()).forEach(File::delete);

这将仅删除来自ABC(及其子目录)的文件:

Files.walk(Paths.get("C:/test/ABC/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

^ 这个版本需要处理 IOException 异常


2
第二个不会删除子目录(已测试) - edwise
1
@edwise 是的,它会删除ABC目录下的所有文件以及子目录中的所有文件。这句英文有点含糊不清。 - NonlinearFruit

14

或者在Java 8中使用:

try {
  Files.newDirectoryStream( directory ).forEach( file -> {
    try { Files.delete( file ); }
    catch ( IOException e ) { throw new UncheckedIOException(e); }
  } );
}
catch ( IOException e ) {
  e.printStackTrace();
}

遗憾的是异常处理太笨重了,否则它本可以只有一行代码。


你如何确定文件确实是文件而不是目录? - Stephan
1
它还会删除目录,因此它不是主题中问题的解决方案。 - Marx

7

rm -rfFileUtils.cleanDirectory更高效。

虽然不是一行代码的解决方案,但在广泛的基准测试后,我们发现使用rm -rf比使用FileUtils.cleanDirectory快多倍.

当然,如果您的目录很小或简单,则无关紧要,但在我们的情况下,我们有多个千兆字节和深度嵌套的子目录,使用FileUtils.cleanDirectory需要超过10分钟,而使用rm -rf只需要1分钟。

这是我们粗略的Java实现:

// Delete directory given and all subdirectories and files (i.e. recursively).
//
static public boolean clearDirectory( 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();

        file.mkdirs(); // Since we only want to clear the directory and not delete it, we need to re-create the directory.

        return true;
    }

    return false;

}

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

6
public class DeleteFile {
    public static void main(String[] args) {
        String path="D:\test"; 
        File file = new File(path);
        File[] files = file.listFiles(); 
        for (File f:files) 
        {if (f.isFile() && f.exists) 
            { f.delete();
system.out.println("successfully deleted");
            }else{
system.out.println("cant delete a file due to open or error");
} }  }}

太好了... 这正是我寻找的代码示例,尽管有一些小的语法错误。只需要将.exists替换为.exists()并将system.out替换为System.out即可。 - Supercoder

3
删除目录"C:\Example"中的所有文件,请执行以下操作:
File file = new File("C:\\Example");      
String[] myFiles;    
if (file.isDirectory()) {
    myFiles = file.list();
    for (int i = 0; i < myFiles.length; i++) {
        File myFile = new File(file, myFiles[i]); 
        myFile.delete();
    }
}

2

以下是使用Java 8 Stream删除文件夹中所有内容(包括子目录,但不包括文件夹本身)的另一种解决方案:

用法:

Path folder = Paths.get("/tmp/folder");
CleanFolder.clean(folder);

以及代码:

public interface CleanFolder {
    static void clean(Path folder) throws IOException {

        Function<Path, Stream<Path>> walk = p -> {
            try { return Files.walk(p);
        } catch (IOException e) {
            return Stream.empty();
        }};

        Consumer<Path> delete = p -> {
            try {
                Files.delete(p);
            } catch (IOException e) {
            }
        };

        Files.list(folder)
            .flatMap(walk)
            .sorted(Comparator.reverseOrder())
            .forEach(delete);
    }
}

每个使用Files.walk或Files.delete的流解决方案的问题在于这些方法会抛出IOException,这些异常在流中处理起来很麻烦。我尝试创建一个尽可能简洁的解决方案。

在walk函数中,最好返回一个空流(Stream.empty())而不是返回null。这样更加简洁明了,而且函数总是返回一个流。应尽可能避免使用null。 - kaba713
谢谢,我用了你的建议来改进答案。 - hijack

2
我认为这个方案可行(基于NonlinearFruit先前的回答):最初的回答
Files.walk(Paths.get("C:/test/ABC/"))
                .sorted(Comparator.reverseOrder())
                .map(Path::toFile)
                .filter(item -> !item.getPath().equals("C:/test/ABC/"))
                .forEach(File::delete);

Cheers!


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