23 ответов:
вы должны проверить apache's commons-io. Он имеет FileUtils класс, который будет делать то, что вы хотите.
FileUtils.deleteDirectory(new File("directory"));
С 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); }
в 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; } });
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. Процессы являются частными, но их поведение должно быть очевидным.)
однострочное решение (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);
просто увидел, что мое решение более или менее такое же, как у Эриксона, просто упаковано как статический метод. Бросьте это где-нибудь, это намного легче, чем установка всех 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(); } }
решение со стеком и без рекурсивных методов:
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(); } }
гуавы С
Files.deleteRecursively(File)поддерживает до гуавы 9.С гуава 10:
не рекомендуется. этот метод страдает от плохого обнаружения символических ссылок и условий гонки. Эта функциональность может быть поддержана соответствующим образом только путем обстрела команды операционной системы, такой как
rm -rfилиdel /s. этот метод планируется удалить из Guava в Guava release 11.0.таким образом, нет такого метода в гуавы 11.
Если у вас есть весна, вы можете использовать FileSystemUtils.deleteRecursively:
import org.springframework.util.FileSystemUtils; boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
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) { /* ... */ } });
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(); }
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(); } }
два способа отказа с символическими ссылками и приведенным выше кодом... и не знаю решения.
Способ #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:
вы могли бы использовать:
org.apache.commons.io.FileUtils.deleteQuietly(destFile);удаляет файл, не выдавая исключение. Если файл является каталогом, удалите его и все подкаталоги. Разница между файлами.удалить() и этот метод: Каталог для удаления не обязательно должен быть пустым. При невозможности удаления файла или каталога исключения не создаются.
в устаревших проектах, мне нужно создать 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()); } }
оптимальное решение, которое обрабатывает исключение последовательно с подходом, что исключение, вызванное из метода, всегда должно описывать, что этот метод пытался (и не смог) сделать:
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); } }
вот основной метод bare bones, который принимает аргумент командной строки, вам может потребоваться добавить свою собственную проверку ошибок или сформировать ее так, как вы считаете нужным.
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(); } } }Я надеюсь, что помогает!
без Commons IO и
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(); }
ниже код рекурсивно удалить все содержимое в данной папке.
boolean deleteDirectory(File directoryToBeDeleted) { File[] allContents = directoryToBeDeleted.listFiles(); if (allContents != null) { for (File file : allContents) { deleteDirectory(file); } } return directoryToBeDeleted.delete(); }
возможно, решением этой проблемы может быть переопределение метода 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(); } } }
в то время как файлы могут быть легко удалены с помощью файла.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(); } } } } } }
я закодировал эту процедуру, которая имеет 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); } }
ну, допустим пример,
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()); } }для получения дополнительной информации см. ниже ресурсы
Comments