Видалення каталогів рекурсивно на Java


382

Чи є можливість видалити цілі каталоги рекурентно на Java?

У звичайному випадку можна видалити порожній каталог. Однак якщо мова йде про видалення цілих каталогів із вмістом, це вже не так просто.

Як видалити цілі каталоги зі вмістом на Java?


4
File.delete () повинен просто повернути помилкове після виклику його з не порожнім каталогом.
Ben S

Якщо ви використовуєте Java 8, дивіться відповідь @ RoK.
Робін

Відповіді:


462

Ви повинні ознайомитись із загальною частиною Apache-io . У ньому є клас FileUtils, який буде робити те, що ви хочете.

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

3
Ця функція, ймовірно, прикриває код, який Еріксон надав у своїй відповіді.
paweloque

14
Це трохи ретельніше. Він обробляє такі речі, як символічні посилання правильно в Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Стів K



Навіщо додавати іншу залежність, коли у Java є об'єкт поза коробкою? Дивіться відповідь RoK на цій сторінці, або stackoverflow.com/questions/35988192/…
foo

190

З Java 7 ми можемо, нарешті, зробити це надійним виявленням посилань. (Я не вважаю, що спільнота Apache-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);
}

11
File.delete () не має такої функціональності.
Ben S

14
@Erickson: Чи FileNotFoundException не є поганим винятком для помилки видалення? Якщо файл справді більше не існує, його, мабуть, уже видалили, а це означає, що семантично видалення не вийшло з ладу - він не мав нічого спільного. І якщо це не вдалося з якоїсь іншої причини, це було не тому, що файл не був знайдений.
Лоуренс Дол

46
Будь ДУЖЕ Дбайливим . Це призведе до повалення символів. Якщо ви працюєте, наприклад, на Linux і маєте папку fooз таким посиланням foo/link, що link->/виклик delete(new File(foo)) видалить стільки вашої файлової системи, скільки дозволено користувачеві !!
Мікель

4
@Miquel Це не має сенсу - Чому ми хочемо бути обережними? Безумовно, суть наданого коду полягає в тому, щоб видалити цілий каталог, що, як видається, робить. Я не розумію, яка тут небезпека.
Joehot200

12
@ Joehot200 ви маєте рацію, виклик видалення в каталозі symlink не видалить каталог, лише саме посилання. Видалення каталогу фактично вимагатиме чіткого дотримання символьної посилання за допомогою ReadSymbolicLink . Моє ліжко! Добре помічений
Мікель

148

У Java 7+ ви можете використовувати Filesклас. Код дуже простий:

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

2
Це рішення здається дуже елегантним і зовсім не містить логіки переходу каталогів!
Нуль3

1
"Щоб знайти перлину зануритися глибоко в океан." Це, безумовно, новітнє рішення, яке я знайшов. Довелося зануритися вглиб, щоб знайти його. Блискуче!
Василь Муса

20
"Код" НЕ "дуже простий", щоб просто видалити dir :-) Але ей, це найкраще рішення в чистому Java, який я вважаю.
Мат

1
Зверніть увагу, що перевантаження walkFileTree, використане тут, " не переходить до символічних посилань ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Стефан

1
Ви, ймовірно, повинні зателефонувати super.postVisitDirectory(dir, exc);у своєму postVisitDirectoryметоді, щоб підірватись, якщо прогулянка не змогла перерахувати каталог.
Том Андерсон

68

Однолінійне рішення (Java8) для видалення всіх файлів і каталогів рекурсивно, включаючи стартовий каталог:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .forEach(File::delete);

Ми використовуємо компаратор для зворотного порядку, інакше файл :: delete не зможе видалити, можливо, не порожній каталог. Отже, якщо ви хочете зберігати каталоги та видаляти лише файли, просто видаліть компаратор у сортованому () або видаліть сортування повністю та додайте фільтр файлів:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

1
Для видалення всіх каталогів потрібно змінити тип у першому на .sorted (Comparator :: reverseOrder) . В іншому випадку батьківський каталог впорядковується перед дитиною, тому він не видаляється, оскільки він не порожній. Чудова відповідь для тих, хто використовує Java 8!
Робін

1
Правильний шлях .sorted(Comparator.reverseOrder())Пропозиція Comparator::reverseOrderдійсно НЕ працює. Див: stackoverflow.com/questions/43036611 / ...
user1156544

4
Робін, зверни увагу на знак мінус "-o1.compareTo (o2)". Це те саме, що .sorted (Comparator.reverseOrder)
RoK

Чи Files.walk є послідовним? Або ця відповідь потрібна дляEachOrряд замість forEach, щоб уникнути спроб видалити непорожні каталоги?
Сріблення

Просто використовуйте:, .sorted((f1, f2) -> f2.compareTo(f1))порівнюючи f2з, f1а не f1з f2.
Beto Neto

67

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 . Процеси приватні, але його поведінка має бути очевидною.)


Я знаходжу одну проблему з Files.walkFileTree - вона недостатня для реалізації версії рекурсивного видалення, де ви продовжуєте видаляти файли, поки не закінчуються параметри. Це адекватно для невдалої версії, але невдала швидкість - це не завжди те, що ви хочете (наприклад, якщо ви чистите тимчасові файли, ви хочете видалити зараз, а не швидко.)
Trejkaz,

Я не бачу, чому це правда. Ви можете впоратися з помилками, як хочете - від вас не вимагається швидко провалюватися. Єдине питання, яке я міг передбачити, - це те, що він може не обробляти нові файли, що створюються під час прогулянки по поточному каталогу, але це унікальна ситуація, яка краще підходить для користувацького рішення.
Тревор Робінсон

1
Якщо ви придушите помилку VisitFile і виклику walkFileTree в одному файлі, який не вдалося, ви не отримаєте помилки (тому visitFile повинен поширити будь-яку помилку, що виникає.) Якщо ви видаляєте каталог і не вдалося видалити один файл, єдиний зворотний виклик називається є postVisitDirectory. тобто він не відвідує інші файли в каталозі, якщо ви отримуєте помилку під час відвідування одного файлу. Це я маю на увазі. Я впевнений, що, мабуть, є спосіб подолати це, але до того моменту, як ми дійшли до цього моменту, ми вже написали більше коду, ніж традиційна рекурсивна програма для видалення, тому ми вирішили не використовувати його.
Трейказ

Дякую за ваш 1-й код, він був корисним для мене, але я мусив його змінити, оскільки він не завершив простий дельтрейд: мені довелося ігнорувати виняток у "postVisitDirectory" і повертати CONTINUE незалежно, оскільки наступне просте дерево не могло повністю Видалити: Каталог, всередині якого був інший каталог, всередині якого був один файл. Все це настільки ж просто / нормально, як у Windows.
Президент Dreamspace

Все почалося з ява.nio.file.DirectoryNotEmptyException, який я отримав. Я дізнався випадок, коли використовується visitFileFailed. Якщо ваша структура каталогу містить посилання типу "перехід" у Windows. Це може викликати у вас 2 проблеми: *) Files.walkFileTree переходить за посиланням на перехід і видаляє все там. *) Якщо цільовий каталог стику вже видалено, то розбір посилання Files.walkFileTree не вдається з NoSuchFileException, який потрапляє у visitFileFailed.
Андрес Луук

34

Щойно побачив, що моє рішення більш-менш збігається з еріксоном, просто упакованим як статичний метод. Відкиньте це кудись, це набагато легша вага, ніж установка всіх 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();
    }
}

20

Рішення зі стеком та без рекурсивних методів:

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

2
+1 за використання стека. Це буде працювати з каталогами, які містять глибокі рівні вкладених підкаталогів, тоді як інші підходи, засновані на стеці, не зможуть.
Натан Осман

4
Зважаючи на те, що у вас зазвичай не виникає проблем з введенням двох сотень викликів методів, я думаю, ви, швидше за все, натрапите на обмеження файлової системи набагато раніше.
Бомбе

2
Будьте обережні з list*методами для класу java.io.File. З Javadocs: "Повертає нуль, якщо це абстрактне ім'я шляху не позначає каталог, або якщо виникає помилка вводу / виводу." Отже: if (currList.length > 0) {стаєif (null != currList && currList.length > 0) {
кевінарпе

1
Я використовую ArrayDeque замість стека, який трохи швидше. (несинхронізовано)
Wytze


15

Гуави не було Files.deleteRecursively(File)підтримується до гуави 9 .

Від Гуави 10 :

Застарілий. Цей метод страждає від поганих умов виявлення симлінк та перегонів. Цю функціональність можна підтримувати належним чином лише шляхом обстрілу з такою командою операційної системи, як rm -rfабо del /s. Цей спосіб планується видалити з Guava у випуску Guava 11.0.

Тому в Гуаві 11 такого способу немає .


6
Дуже погано. Обстріли здаються трохи грубими і не портативними. Якщо версія Apache commons працює належним чином, то, імовірно, це неможливо здійснити.
Ендрю Маккінлай

6
@andrew Реалізація Apache Commons повинна мати подібні проблеми з тими, які спричиняють Guava видалити їх реалізацію, див. code.google.com/p/guava-libraries/isissue/detail?id=365
orip

Версія apache commons виявляє символьні посилання та просто не обходить файли дітей.
Аякс

5
Guava 21.0 додав це як MoreFiles.deleteRecursively () .
Роберт Флемінг

12
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) { /* ... */ }
      });

2
Це допомогло мені придумати версію Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
Джеймс Уорд,

Чи потрібне сортування насправді? walkМетод вже гарантує глибину першого обходу.
VGR

Порівняльник може бути перероблений, Collections.reverseOrder()тому ваш код for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))припускає, що він статично імпортований.
namero999

@ namero999 Ви маєте на увазі Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Джефф

@Jeff впевнений, що ти маєш рацію, здебільшого пішов на згадку там :)
namero999

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

5
Розширена версія з бульовим значенням повернення та без дублювання: pastebin.com/PqJyzQUx
Ерік Каплун

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

Хороший код, але є одна помилка, коли вона виправлена, вона працює. Рядок f.delete()під назвою deleteDirectory(f)буде кидати NoSuchFileException, оскільки deleteDirectory(f)цей файл вже видаляє. Кожен каталог стане шлях, коли його передають deleteDirectory(f)та видаляють path.delete(). Тому f.delete()в if f.isDerectoryрозділі нам це не потрібно . Отже, просто видаліть f.delete();під deleteDirectory (f) і воно буде працювати.
Трієу Нгуєн

5

Два способи вийти з ладу за допомогою посилань і вищевказаного коду ... і не знаю рішення.

Шлях №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 видалить лише посилання. Вам потрібно використовувати щось на зразок цього, видаліть файли, що відмінили: "знайти -L dirtodelete -type f -exec rm {} \;".

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

4

Ви можете використовувати:

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

Видаляє файл, ніколи не викидаючи виняток. Якщо файл - це каталог, видаліть його та всі підкаталоги. Різниця між File.delete () і цим методом полягає в наступному: Каталог, який потрібно видалити, не повинен бути порожнім. Не виключаються винятки, коли файл чи каталог не можна видалити.


4

Оптимальне рішення, яке обробляє виняток послідовно із підходом, що виняток, викинутий із методу, завжди повинен описувати, що цей метод намагався (і що не вдалося) зробити:

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

3

У застарілих проектах мені потрібно створити нативний 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());
    }

}

3

Нижче коду рекурсивно видаляйте весь вміст у певній папці.

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

2

Ось основний метод з голими кістками, який приймає аргумент командного рядка.

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

Я сподіваюся, що це допомагає!


1

Можливо, вирішенням цієї проблеми може стати повторне доповнення методу видалення класу File за допомогою коду з відповіді erickson:

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

1
Я думаю, що вона реалізована так, як це імітує поведінку більшості утиліт команди командних оболонок, таких як "rm", "rmdir" та "del". З двох альтернатив, поточна реалізація, безумовно, мінімізує загальний потенціал несподіванки (і гніву). Це не зміниться.
erickson

4
Як правило, єдині пакети Java JRE, які я бачу розширені, є від Swing. Зазвичай розширення інших класів, таких як java.io.File, є поганою ідеєю, оскільки має можливість змусити речі діяти несподівано.
Едді

1

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

0

Хоча файли можна легко видалити за допомогою 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();
                        }
                    }
                }
            }
        }
    }

0

Я зашифрував цю процедуру, яка має 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);
    }
}

0

Що ж, припустимо приклад,

import java.io.File;
import java.io.IOException;

public class DeleteDirectory
{
   private static final String folder = "D:/project/java";

   public static void main(String[] args) throws IOException
   {
      File fl = new File(folder);
      if(!fl.exists()) // checking if directory exists
      {
         System.out.println("Sorry!! directory doesn't exist.");
      }
      else
      {
         DeleteDirectory dd = new DeleteDirectory();
         dd.deleteDirectory(fl);
      }
   }

   public void deleteDirectory(File file) throws IOException
   {
      if(file.isDirectory())
      {
         if(file.list().length == 0)
         { 
            deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
         }
         else
         {
            File fe[] = file.listFiles();
            for(File deleteFile : fe)
            {
               deleteDirectory(deleteFile); // recursive call
            }
            if(file.list().length == 0)
            {
               deleteEmptyDirectory(file);
            }
         }
      }
      else
      {
         file.delete();
         System.out.println("File deleted : " + file.getAbsolutePath());
      }
   }

   private void deleteEmptyDirectory(File fi)
   {
      fi.delete();
      System.out.println("Directory deleted : " + fi.getAbsolutePath());
   }
}

Для отримання додаткової інформації дивіться нижче ресурси

Видалити каталог


0

rm -rfбув набагато ефективнішим, ніж FileUtils.deleteDirectory.

Після широкого бенчмаркінгу ми виявили, що використання rm -rfбуло в кілька разів швидше, ніж використання FileUtils.deleteDirectory.

Звичайно, якщо у вас невеликий або простий каталог, це не має значення, але в нашому випадку у нас було кілька гігабайт і глибоко вкладені підкаталоги, де це займе понад 10 хвилин FileUtils.deleteDirectoryі лише 1 хвилину rm -rf.

Ось наша груба реалізація 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;

}

Варто спробувати, якщо ви маєте справу з великими або складними каталогами.


Це працює кросп-платформа ??
OneCricketeer

@ cricket_007 Які платформи?
Джошуа Пінтер

Windows? OpenWrt? BSD?
OneCricketeer

1
@ cricket_007 Однозначно не Windows. Це було протестовано та використано на Android та macOS.
Джошуа Пінтер

0

Гуави забезпечує однострочнікі: MoreFiles.deleteRecursively().

На відміну від багатьох спільних прикладів, він обчислює символічні посилання і не видаляє (за замовчуванням) файли за межами передбаченого шляху.

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