Удалить все файлы в каталоге (но не в каталоге) - одно линейное решение

201

Я хочу удалить все файлы внутри каталога ABC.

При попытке с FileUtils.deleteDirectory(new File("C:/test/ABC/"));ним также удаляет папку ABC.

Есть ли решение с одним вкладышем, где я могу удалить файлы внутри каталога, но не в каталоге?

Фахим Паркар
источник
2
Это потому, что .deleteDirectory (даже имя подразумевает это) используется для удаления каталогов. Он получит каталог, в котором он находится, если файл не является каталогом.
user1534664
Попробуйте поискать другие функции внутри класса FileUtils, которые удаляют файлы вместо каталогов.
user1534664
1
Зачем вам конкретно нужен однострочник? Производительность не может быть критерием, потому что любой сторонний библиотечный метод будет делать это только рекурсивно. Так что это даст вам ту же производительность?
Рохит Джайн
1
Одна вещь, которую вы можете сделать, это удалить каталог, а затем заново создать его. Мы обнаружили, что использование rm -rf directory; mkdir directoryбыло быстрее, чем использование FileUtils.cleanDirectory.
Джошуа Пинтер

Ответы:

362
import org.apache.commons.io.FileUtils;

FileUtils.cleanDirectory(directory); 

Этот метод доступен в том же файле. Это также рекурсивно удалит все вложенные папки и файлы в них.

Docs: org.apache.commons.io.FileUtils.cleanDirectory

Reddy
источник
49
Хороший, также, чтобы препятствовать людям искать это; вот импорт: import org.apache.commons.io.FileUtils;
Пол Грегуар
5
Я все еще должен посмотреть, почему импорт не может быть найден. Это потому, что нужно скачать его с apache.org .
Томаш Зато - Восстановить Монику
красивое решение. Проверьте эту библиотеку по gradle: compile "commons-io: commons-io: +"
Лео Нгуен,
1
Зависимость Gradle - группа компиляции: 'commons-io', имя: 'commons-io', версия: '2.5'.
Джайдев
Обратите внимание, мы обнаружили, что вызов rm -rf directoryбыл намного эффективнее, чем использование FileUtils.cleanDirectory.
Джошуа Пинтер
267

Вы имеете в виду как?

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

Это приведет к удалению только файлов, а не каталогов.

Питер Лори
источник
65
Это, безусловно, лучший ответ, так как он не использует внешнюю библиотеку!
AlexWien
10
@amar, но даже тогда: когда есть стандартный метод, нет абсолютно никакой причины использовать внешний метод, который делает то же самое. Однажды он может захотеть избавиться от библиотеки, или библиотека больше не поддерживается, или ей не разрешено использовать библиотеку по лицензионным причинам и т. Д. (Это может не быть проблемой для этой конкретной библиотеки, но относится к много других)
AlexWien
10
Это не удалит все, если у вас есть подкаталоги внутри корневого каталога "dir".
Tiago
2
@TiagoT Правда, это не удалит подкаталоги, которые не являются пустыми.
Питер Лори
4
for(File file: dir.listFiles())вероятно, подразумевается как .... for (File file : new java.io.File("C:\\DeleteMeFolder").listFiles())...
Хартмут П.
62

Ответ Питера Лоури великолепен, потому что он прост и не зависит от чего-то особенного, и именно так вы должны это делать. Если вам нужно что-то, что также удаляет подкаталоги и их содержимое, используйте рекурсию:

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()метод.

ChrisB
источник
1
С другой стороны, если никто не первым использует внешнюю библиотеку, то менее вероятно, что другие будут ожидать подобного поведения в этой внешней библиотеке, и менее вероятно, что они будут искать ее там ... разве у нас недостаточно Не изобретено здесь, там? Если библиотека сплоченная и ее легко добавить в мой проект, то я почти всегда предпочитаю добавлять библиотеку.
JB Rainsberger
33

Java 8 Stream

Это удаляет только файлы из 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

NonlinearFruit
источник
1
Второй не удаляет подкаталоги (проверено)
edwise
1
@edwise Да, он удаляет все файлы из ABC и все файлы из подкаталогов. Английский немного двусмысленный.
Нелинейный
11

Или использовать это в Java 8:

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

Жаль, что обработка исключений такая громоздкая, иначе это будет однострочник ...

Кристиан Улленбум
источник
Как вы знаете , что файл IS файл на самом деле и не каталог?
Стефан
1
Он также удаляет каталог, так что это не решение проблемы из темы
Marx
5
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");
} }  }}
Манбумиху Манаван
источник
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, который является трудной для обработки в потоках.

Я попытался создать решение, которое было бы более кратким.

похищать
источник
Вместо того, чтобы возвращать нуль в функции ходьбы, было бы лучше вернуть пустой поток (Stream.empty ()). Это чище, и функция всегда возвращает поток. По возможности следует избегать нуля.
kaba713
Спасибо, я улучшил ответ с вашим предложением
угон
2

Для удаления всех файлов из каталога скажите «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

rm -rfбыл намного более производительным, чем FileUtils.cleanDirectory.

Не однострочное решение, но после обширного тестирования мы обнаружили, что использование rm -rfбыло в несколько раз быстрее, чем использование FileUtils.cleanDirectory.

Конечно, если у вас небольшой или простой каталог, это не имеет значения, но в нашем случае у нас было несколько гигабайт и вложенные вложенные подкаталоги, где это заняло бы более 10 минут FileUtils.cleanDirectoryи только 1 минуту rm -rf.

Вот наша грубая реализация 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;

}

Стоит попробовать, если вы имеете дело с большими или сложными каталогами.

Джошуа Пинтер
источник
1
package com;
import java.io.File;
public class Delete {
    public static void main(String[] args) {

        String files; 
        File file = new File("D:\\del\\yc\\gh");
        File[] listOfFiles = file.listFiles(); 
        for (int i = 0; i < listOfFiles.length; i++) 
        {
            if (listOfFiles[i].isFile()) 
            {
                files = listOfFiles[i].getName();
                System.out.println(files);
                if(!files.equalsIgnoreCase("Scan.pdf"))
                {
                    boolean issuccess=new File(listOfFiles[i].toString()).delete();
                    System.err.println("Deletion Success "+issuccess);
                }
            }
        }
    }
}

Если вы хотите удалить все файлы, удалите

if(!files.equalsIgnoreCase("Scan.pdf"))

Заявление это будет работать.

Махеш
источник
0

Я думаю, что это будет работать (основываясь на предыдущем ответе 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);

Ура!

dansouza
источник