Удалить каталоги рекурсивно в Java

382

Есть ли способ рекурсивного удаления целых каталогов в Java?

В обычном случае можно удалить пустой каталог. Однако, когда дело доходит до удаления целых каталогов с содержимым, это уже не так просто.

Как вы удаляете целые каталоги с содержимым в Java?

paweloque
источник
4
File.delete () должен просто возвращать false при вызове его с непустым каталогом.
Бен С
Если вы используете Java 8, смотрите ответ @ RoK.
Робин

Ответы:

462

Вы должны проверить Apache Commons-IO . Он имеет класс FileUtils, который будет делать то, что вы хотите.

FileUtils.deleteDirectory(new File("directory"));
Стив К
источник
3
Эта функция, вероятно, оборачивает код, предоставленный Эриксоном в своем ответе.
Павелок
14
Это немного более тщательно. Он правильно обрабатывает такие вещи, как символические ссылки в Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Стив К
1
@Steve K, URL-адрес: svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/…
Ричард Е.Б.
Зачем добавлять еще одну зависимость, когда у Java есть средство из коробки? См. Ответ РК на этой странице или stackoverflow.com/questions/35988192/…
foo
190

С Java 7 мы можем наконец сделать это с надежным обнаружением символической ссылки. (Я не считаю, что Apache commons-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 () не имеет этой функциональности.
Бен С
14
@Erickson: не является ли FileNotFoundException плохим исключением для ошибки удаления? Если файл действительно больше не существует, он, должно быть, уже был удален, что означает, что семантически удаление не завершилось неудачей - ему нечего было делать. И если это не удалось по какой-то другой причине, это не потому, что файл не был найден.
Лоуренс Дол
46
Будьте ОЧЕНЬ ОСТОРОЖНЫ . Это будет разыменовывать символические ссылки. Если вы, например, используете Linux, и у вас есть папка fooс такой ссылкой foo/link, что при link->/вызове delete(new File(foo)) будет удалено столько файловой системы, сколько разрешено вашему пользователю !!
Микель
4
@Miquel Это не имеет смысла - почему мы хотим быть осторожными? Конечно, смысл предоставленного кода заключается в удалении всего каталога, что он и делает. Я не понимаю, в чем тут опасность.
Joehot200
12
@ Joehot200 Вы правы, вызов delete для символьной ссылки на каталог не приведет к удалению каталога, а только самой символической ссылки. Удаление каталога на самом деле требует явной ссылки на символическую ссылку с использованием 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
«Найти жемчужное погружение глубоко в океан». Это, безусловно, самое лучшее решение, которое я нашел. Пришлось нырнуть глубоко, чтобы найти это. Brilliant!
Василий Муса
20
"Код" НЕ "очень прост", чтобы просто удалить каталог :-) Но эй, это лучшее решение в чистой 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);

Мы используем компаратор для обратного порядка, иначе File :: delete не сможет удалить, возможно, непустую директорию. Итак, если вы хотите сохранить каталоги и удалять только файлы, просто удалите компаратор в sorted () или полностью удалите сортировку и добавьте фильтр файлов:

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)
РК
Является ли Files.walk последовательным? Или этот ответ нужен для forEachOrdered вместо forEach, чтобы избежать попыток удалить непустые каталоги?
Silwing
Просто используйте: .sorted((f1, f2) -> f2.compareTo(f1))в сравнении f2с f1вместо f1с f2.
Бето Нето
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. то есть, он не посещает другие файлы в каталоге, если вы получаете ошибку при посещении одного файла. Это то, что я имею в виду. Я уверен, что, возможно, есть какой-то способ обойти это, но к тому времени, когда мы добрались до этого момента, мы уже написали больше кода, чем традиционная процедура рекурсивного удаления, поэтому мы решили не использовать его.
Трейказ
Спасибо за ваш первый код, он был полезен для меня, но мне пришлось его изменить, потому что он не завершил простое deltree: мне пришлось игнорировать исключение в "postVisitDirectory" и возвращать CONTINUE независимо от того, что следующее простое дерево не могло полностью быть удаленным: каталог, внутри которого был другой каталог, внутри которого был один файл. Все это так же просто / нормально, как в Windows.
Президент Dreamspace
Все началось с java.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();
    }
}
Paulitex
источник
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();
    }
}
trianam
источник
2
+1 за использование стека. Это будет работать с каталогами, которые содержат глубокие уровни вложенных подкаталогов, в то время как другие основанные на стеке подходы потерпят неудачу.
Натан Осман
4
Видя, что у вас обычно нет проблем с вложением нескольких сотен вызовов методов, я думаю, что вы, вероятно, столкнетесь с ограничениями файловой системы намного раньше.
Бомба
2
Будьте осторожны с list*методами для класса java.io.File. Из Javadocs: «Возвращает ноль, если это абстрактное имя пути не обозначает каталог или если произошла ошибка ввода-вывода». Итак: if (currList.length > 0) {становитсяif (null != currList && currList.length > 0) {
Кевинарпе
1
Я использую ArrayDeque вместо стека, который немного быстрее. (несинхронизировано)
Wytze
15

Если у вас есть Spring, вы можете использовать FileSystemUtils.deleteRecursively :

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
Бен Хатчисон
источник
15

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

Из гуавы 10 :

Устаревшее. Этот метод страдает от плохого обнаружения символических ссылок и условий гонки. Эта функциональность может поддерживаться подходящим образом только путем предоставления команды операционной системе, такой как rm -rfили del /s. Этот метод планируется удалить из Гуавы в версии 11.0.

Поэтому в Guava 11 такого метода нет .

Эндрю Маккинли
источник
6
Очень плохо. Выстрел кажется немного грубым и не переносимым. Если версия Apache Commons работает правильно, то, по-видимому, это не невозможно реализовать.
Эндрю МакКинлей
6
@andrew У реализации Apache Commons должны быть проблемы, аналогичные тем, которые заставляют Guava удалить их реализацию, см. code.google.com/p/guava-libraries/issues/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) { /* ... */ }
      });
user3669782
источник
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))
Джефф
@Джефф совершенно уверен, что ты прав, в основном ходил туда по памяти :)
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();
}
AdamOutler
источник
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();
    }
}
vladicho
источник
Хороший код, но есть одна ошибка, когда она исправлена, она работает. Строка 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 удалит только ссылку. Вам нужно использовать что-то вроде этого, чтобы удалить разыменованные файлы: "find -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);
    }
}
AgilePro
источник
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

Возможно, решением этой проблемы может быть переопределение метода delete класса File с использованием кода из ответа Эриксона:

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();
    }
  }
}
paweloque
источник
1
Я думаю, что он реализован так, чтобы имитировать поведение большинства утилит командной оболочки, таких как «rm», «rmdir» и «del». Из двух альтернатив текущая реализация определенно минимизирует общий потенциал неожиданности (и гнева). Это не изменится.
erickson
4
Как правило, только расширенные пакеты Java JRE от Swing. Как правило, расширение других классов, таких как java.io.File, является плохой идеей, поскольку оно может привести к неожиданным действиям.
Эдди
1

Без общего ввода-вывода и <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);
    }
}
datahaki
источник
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 Какие платформы?
Джошуа Пинтер
Окна? OpenWrt? BSD?
OneCricketeer
1
@ cricket_007 Определенно не Windows. Это было проверено и использовано на Android и MacOS.
Джошуа Пинтер
0

Гуава предоставляет однострочник MoreFiles.deleteRecursively().

В отличие от многих общих примеров, он учитывает символические ссылки и не будет (по умолчанию) удалять файлы за пределами указанного пути.

dimo414
источник