Видалити всі файли в каталозі (але не в каталозі) - рішення одного вкладиша


201

Я хочу видалити всі файли з каталогу ABC.

Коли я спробував з FileUtils.deleteDirectory(new File("C:/test/ABC/"));ним, також видаляє папку ABC.

Чи є одне рішення вкладиша, де я можу видаляти файли всередині каталогу, а не каталог?


2
Це тому, що .deleteDirectory (навіть назва це означає) використовується для видалення каталогу. Він отримає каталог, в якому знаходиться, якщо файл не є каталогом.
користувач1534664

Спробуйте шукати інші функції всередині класу FileUtils, які видаляють файли замість каталогу.
користувач1534664


1
Для чого конкретно вам потрібен однолінійний? Ефективність не може бути критерієм, оскільки будь-який сторонній метод бібліотеки буде робити це лише рекурсивно. Так це дало б вам таку саму виставу?
Rohit Jain

1
Одне, що можна зробити, - це видалити каталог, а потім знову створити його. Ми виявили, що використання rm -rf directory; mkdir directoryбуло швидше, ніж використання FileUtils.cleanDirectory.
Джошуа Пінтер

Відповіді:


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

FileUtils.cleanDirectory(directory); 

Цей спосіб доступний в одному файлі. Це також буде рекурсивно видаляти всі підпапки та файли під ними.

Документи: org.apache.commons.io.FileUtils.cleanDirectory


49
Хороший, щоб також не допустити людей дивитися на це; ось імпорт: імпорт 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" є підкаталоги.
Тіаго

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


1
З іншого боку, якщо ніхто не буде першим, хто користується зовнішньою бібліотекою, то менше шансів, що інші сподіваються знайти подібну поведінку у цій зовнішній бібліотеці, і менша ймовірність, що вони там будуть шукати ... хіба нам не вистачає Не придумали тут? Якщо бібліотека є згуртованою і легко додати до свого проекту, то я майже завжди вважаю за краще додавати бібліотеку.
JB Rainsberger

33

Потік 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


1
Другий не видаляє підкаталоги (тестовано)
також

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

Шкода, що обробка виключень настільки об'ємна, інакше це буде однолінійний ...


Звідки ви знаєте, що файл - це власне файл, а не каталог?
Стефан

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

Ура!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.