Java dizinlerini yinelemeli olarak silme


382

Tüm dizinleri tekrar tekrar Java ile silmenin bir yolu var mı?

Normal durumda boş bir dizini silmek mümkündür. Bununla birlikte, tüm dizinleri içeriklerle silmek söz konusu olduğunda, artık o kadar basit değil.

Java'da içerik barındıran tüm dizinleri nasıl silebilirsiniz?


4
File.delete () yöntemi, boş olmayan bir dizinle çağrıldığında false değerini döndürmelidir.
Ben S

Java 8 kullanıyorsanız, @ RoK'nın cevabına bakınız.
Robin

Yanıtlar:


462

Apache'nin müştereklerini kontrol etmelisiniz . İstediğinizi yapacak bir FileUtils sınıfına sahiptir.

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

3
Bu işlev muhtemelen erickson'un cevabında verdiği kodu sarar.
paweloque

14
Biraz daha ayrıntılı. Linux / Unix'te sembolik bağlantılar gibi şeyleri doğru şekilde işler. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Steve K



Java'nın kullanıma hazır bir özelliği olduğunda neden başka bir bağımlılık eklemelisiniz? Bu sayfadaki RoK tarafından verilen cevaba bakınız veya stackoverflow.com/questions/35988192/…
foo

190

Java 7 ile bunu güvenilir symlink algılamasıyla yapabiliriz. (Apache'nin müşterilerinin şu anda oluşturulmuş Windows bağlantılarını işlemediği için güvenilir symlink algılamasına sahip olduğunu düşünmüyorum mklink.)

Tarih uğruna, sembolik bağlantıları takip eden Java öncesi 7 cevabı .

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 () bu işlevselliğe sahip değildir.
Ben S

14
@Erickson: FileNotFoundException silme hatası için kötü bir istisna değil mi? Dosya artık orada değilse, daha önce silinmiş olmalıdır, yani anlamsal olarak silme başarısız olmamıştır - yapacak bir şeyleri yoktur. Başka bir nedenden dolayı başarısız olursa, dosya bulunamadığı için değildi.
Lawrence Dol

46
Be çok dikkatli . Bu sembolik bağlantıları kaldıracaktır. Örneğin, linux üzerindeyseniz ve böyle foobir bağlantıya sahip bir klasörünüz varsa , çağrı , kullanıcı sisteminizin izin verdiği kadar dosya sisteminizi siler! foo/linklink->/delete(new File(foo))
Miquel

4
@Miquel Bu mantıklı değil - Neden dikkatli olmak istiyoruz? Şüphesiz, sağlanan kodun amacı, dizinin tamamını, yani göründüğü gibi kaldırmaktır. Burada tehlikenin ne olduğunu anlamıyorum.
Joehot200

12
@ Joehot200 haklısın, bir dizin symlink üzerinde delete çağırmak dizini silmek olmaz, sadece symlink kendisi. Dizinin silinmesi, aslında ReadSymbolicLink kullanarak symlink'i izlemeyi gerektirir . Benim hatam! İyi tespit
Miquel

148

Java 7 ve sonraki sürümlerinde Filessınıfı kullanabilirsiniz . Kod çok basit:

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
Bu çözüm çok zarif görünüyor ve hiçbir dizin geçiş mantığı içermiyor!
Zero3

1
"Okyanusun derinliklerinde bir inci dalışı bulmak için." Bu bulduğum en güzel çözüm. Onu bulmak için derin dalmak zorunda kaldı. Parlak!
Basil Musa

20
"Kod" DEĞİL "çok basit" sadece bir dir silmek için :-) Ama hey bu saf java en iyi çözüm olduğunu düşünüyorum.
Mat

1
Burada kullanılan walkFileTree aşırı yükünün " sembolik bağlantıları takip etmediğini " lütfen unutmayın . (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan

1
Muhtemelen çağırmalıdır super.postVisitDirectory(dir, exc);senin içinde postVisitDirectoryyürüyüş bir dizin liste olamazdı eğer havaya uçurmak için, yöntemin.
Tom Anderson

68

Başlangıç ​​dizini de dahil olmak üzere tüm dosyaları ve dizinleri yinelemeli olarak silmek için tek astarlı bir çözüm (Java8) :

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

Ters sipariş için bir karşılaştırıcı kullanıyoruz, aksi takdirde File :: delete muhtemelen boş olmayan dizini silemez. Bu nedenle, dizinleri saklamak ve yalnızca dosyaları silmek istiyorsanız, karşılaştırıcıyı sıralanmış () olarak kaldırın veya sıralamayı tamamen kaldırın ve dosya filtresi ekleyin:

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

1
Tüm dizinleri silmek için ilkinde sıralamayı .sorted (Comparator :: reverseOrder) olarak değiştirmeniz gerekir . Aksi takdirde üst dizin alt öğeden önce sıralanır ve bu nedenle boş olmadığından silinmez. Java 8 kullananlar için harika bir yanıt!
Robin

1
Doğru yolu .sorted(Comparator.reverseOrder())öneri Comparator::reverseOrderyok değil çalışır. Bkz. Stackoverflow.com/questions/43036611/…
user1156544

4
Robin, eksi işareti "-o1.compareTo (o2)" 'de dikkat et. (Comparator.reverseOrder) .sorted gibi aynı şey
RoK

Files.walk sıralı mı? Yoksa boş olmayan dizinleri silmeyi denemek için bu cevabın forEach yerine forEachOrdered'a ihtiyacı var mı?
Silwing

Sadece kullanın: .sorted((f1, f2) -> f2.compareTo(f1))karşılaştırarak f2ile f1yerine f1sahip f2.
Beto Neto

67

Java 7, symlink işleme özelliğine sahip yürüyüş dizinleri için destek ekledi:

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

Bu platforma özgü yöntemlerden (bu test edilmemiş kodda) bir yedek olarak kullanın :

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'dan alınmıştır . İşlemler özeldir, ancak davranışı açık olmalıdır.)


Files.walkFileTree ile ilgili bir sorun buluyorum - seçenekler bitene kadar dosyaları silmeye devam ettiğiniz özyinelemeli silme sürümünü uygulamak için yetersiz. Başarısız bir sürüm için yeterlidir, ancak başarısızlık her zaman istediğiniz şey değildir (örneğin geçici dosyaları temizliyorsanız, şimdi silmek istiyorsunuz, başarısız hızlı değil.)
Trejkaz

Bunun neden doğru olduğunu anlamıyorum. Hataları istediğiniz gibi halledebilirsiniz - hızlı bir şekilde başarısız olmanız gerekmez. Öngörebileceğim tek sorun, geçerli dizinin yürüyüşü sırasında oluşturulan yeni dosyaları işlemeyebileceğidir, ancak bu, özel bir çözüme daha uygun olan benzersiz bir durumdur.
Trevor Robinson

1
Hatayı visitFile öğesinden kaldırırsanız ve başarısız olan tek bir dosyada walkFileTree öğesini çağırırsanız hata almazsınız (bu nedenle visitFile , oluşan herhangi bir hatayı yaymalıdır .) Bir dizini siliyorsanız ve bir dosyayı silemezseniz, yalnızca geri çağrı postVisitDirectory'dir. yani, bir dosyayı ziyaret ederken bir hata alırsanız dizindeki diğer dosyaları ziyaret etmez. Demek istediğim bu. Muhtemelen bu sorunu çözmek için bir yol var, ama bu noktaya geldiğimizde zaten geleneksel bir özyinelemeli silme rutinden daha fazla kod yazmıştık, bu yüzden kullanmaya karşı karar verdik.
Trejkaz

1. kodunuz için teşekkürler, benim için yararlı oldu, ama basit bir deltree tamamlamadığı için değiştirmek zorunda kaldım: "postVisitDirectory" istisnasını görmezden gelmek ve CONTINUE ne olursa olsun CONTINUE dönmek zorunda kaldı silinecek: İçinde bir dosya olan başka bir dizinin bulunduğu dizin. Bunların hepsi Windows'taki kadar basit / normal.
Dreamspace Başkanı

Her şey bir java.nio.file.DirectoryNotEmptyException aldım. Ben visitFileFailed kullanıldığı durumda öğrendim. Dizin yapınızın pencerelerde bir bağlantı türü bağlantısı varsa. Bu size 2 sorun neden olabilir: *) Files.walkFileTree kavşağa bağlantıyı izler ve orada her şeyi siler. *) Kavşak hedef dizini zaten silinmişse, bağlantıyı Files.walkFileTree tarafından ayrıştırma, visitFileFailed öğesinde yakalanan NoSuchFileException ile başarısız olur.
Andres Luuk

34

Çözümümün erickson'la hemen hemen aynı olduğunu gördüm, sadece statik bir yöntem olarak paketlendi. Bunu bir yere bırakın, (gördüğünüz gibi) oldukça basit bir şey için tüm Apache Commons'ı kurmaktan çok daha hafiftir.

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

Yığınlı ve özyinelemeli yöntemler olmayan bir çözüm:

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
Yığını kullanmak için +1. Bu, diğer yığın tabanlı yaklaşımlar başarısız olurken, iç içe geçmiş alt dizinlerin derin düzeylerini içeren dizinlerle çalışacaktır.
Nathan Osman

4
Genellikle birkaç yüz yöntem çağrısını iç içe yerleştirmede sorun yaşamadığınızı görünce, dosya sistemi kısıtlamalarına çok daha önce gireceğinizi düşünüyorum.
Bombe

2
list*Sınıf yöntemlerine dikkat edin java.io.File. Javadocs'tan: "Bu soyut yol adı bir dizini belirtmiyorsa veya bir G / Ç hatası oluşursa null değerini döndürür." Yani: if (currList.length > 0) {olurif (null != currList && currList.length > 0) {
kevinarpe

1
Biraz daha hızlı bir yığın yerine bir ArrayDeque kullanın. (senkronize
edilmedi


15

Guava , Guava 9'aFiles.deleteRecursively(File) kadar destek vermişti .

Gönderen Guava 10 :

Kullanımdan kaldırıldı. Bu yöntem zayıf sembolik algılama ve yarış koşullarından muzdariptir. Bu işlevsellik uygun şekilde yalnızca rm -rfveya gibi bir işletim sistemi komutuna bombardıman yapılarak desteklenebilir del /s. Bu yöntemin Guava 11.0 sürümünde Guava'dan kaldırılması planlanmaktadır.

Bu nedenle, Guava 11'de böyle bir yöntem yoktur .


6
Çok kötü. Bombardımanı biraz kaba ve taşınabilir değil gibi görünüyor. Apache ortak sürümü düzgün çalışıyorsa, muhtemelen uygulanması imkansız değildir.
Andrew McKinlay

6
@andrew Apache Commons uygulaması, Guava'nın uygulamalarını kaldırmasına neden olanlarla benzer sorunlara sahip olmalıdır, bkz. code.google.com/p/guava-libraries/issues/detail?id=365
orip

Apache commons sürümü sembolik bağlantıları algılar ve sadece dosyanın alt öğelerini geçmez.
Ajax

5
Guava 21.0 bunu MoreFiles.deleteRecursively () olarak ekledi .
Robert Fleming

12
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

Veya aşağıdakileri işlemek istiyorsanız IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });

2
Bu benim Scala versiyonunu geliştirmeme yardımcı oldu:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward

Sıralama gerçekten gerekli mi? walkYöntem zaten bir derinlik ilk geçişi garanti eder.
VGR

Karşılaştırıcı geri dönüştürülebilir, Collections.reverseOrder()böylece kodunuz for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))statik olarak içe aktarılmış kabul edilir.
namero999

Bunu mu demek istediniz Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff

@Jeff haklı olduğunuzdan oldukça emin, çoğunlukla hafızaya gittim :)
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
Boole dönüş değeri olan ve çoğaltma olmadan geliştirilmiş sürüm: pastebin.com/PqJyzQUx
Erik Kaplun

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

Güzel kod, ama bir hata var, düzeltildiğinde işe yarıyor. Çizgi f.delete()altında deleteDirectory(f)çünkü irade NoSuchFileException atar deleteDirectory(f)zaten bu dosyayı silin. Her dizin, iletildiğinde deleteDirectory(f)ve tarafından silindiğinde bir yol haline gelecektir path.delete(). Bu nedenle, gerek yok f.delete()içinde if f.isDerectorybölüm. Yani, f.delete();deleteDirectory (f) altında silin ve işe yarayacaktır.
Trieu Nguyen

5

Symlinks ve yukarıdaki kodla başarısız olmanın iki yolu ... ve çözümü bilmiyorum.

Yol # 1

Bir test oluşturmak için bunu çalıştırın:

echo test > testfile
mkdir dirtodelete
ln -s badlink dirtodelete/badlinktodelete

Test dosyanızı ve test dizininizi burada görebilirsiniz:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Sonra commons-io deleteDirectory () komutunu çalıştırın. Dosyanın bulunmadığını söyleyerek çöküyor. Diğer örneklerin burada ne yaptığından emin değilim. Linux rm komutu basitçe bağlantıyı siler ve dizindeki rm -r de olur.

Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete

Yol # 2

Bir test oluşturmak için bunu çalıştırın:

mkdir testdir
echo test > testdir/testfile
mkdir dirtodelete
ln -s ../testdir dirtodelete/dirlinktodelete

Test dosyanızı ve test dizininizi burada görebilirsiniz:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Ardından, commons-io deleteDirectory () öğenizi veya kişilerin yayınladığı örnek kodu çalıştırın. Yalnızca dizini değil, silinmekte olan dizinin dışındaki sınama dosyanızı da siler. (Dizini dolaylı olarak dereferences ve içeriği siler). rm -r yalnızca bağlantıyı siler. Bunun gibi bir şey kullanmanız gerekir, referansı silinmiş dosyaları silin: "find -L dirtodelete -type f -exec rm {} \;".

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

4

Kullanabilirsin:

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

Asla istisna atmayan bir dosyayı siler. Dosya bir dizinse, dizini ve tüm alt dizinleri silin. File.delete () ve bu yöntem arasındaki fark şunlardır: Silinecek bir dizinin boş olması gerekmez. Bir dosya veya dizin silinemediğinde istisna yapılmaz.


4

Bir yöntemden atılan bir özel durumun her zaman bu yöntemin ne yapmaya çalıştığını (ve başarısız olduğunu) tanımlaması gerektiği yaklaşımıyla tutarlı bir şekilde istisnayı işleyen en uygun çözüm:

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

Eski projelerde, yerel Java kodu oluşturmam gerekiyor. Bu kodu Paulitex koduna benzer şekilde oluşturuyorum. Şuna bakın:

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

Ve birim testi:

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

Aşağıdaki kod, belirli bir klasördeki tüm içeriği tekrar tekrar siler.

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

2

İşte bir komut satırı argümanını kabul eden çıplak kemikler ana yöntemi, kendi hata kontrolünüzü eklemeniz veya uygun gördüğünüz şekilde kalıplamanız gerekebilir.

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

Umarım bu yardımcı olur!


1

Belki de bu sorunun çözümü erickson'un cevabındaki kodu kullanarak File sınıfının delete yöntemini yeniden uygulamak olabilir:

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
Ben "rm", "rmdir" ve "del" gibi çoğu komut kabuğu yardımcı programlarının davranışını taklit gibi uygulandığını düşünüyorum. İki alternatif arasından, mevcut uygulama kesinlikle genel sürpriz (ve öfke) potansiyelini en aza indirmektedir. Değişmeyecek.
erickson

4
Genellikle, genişletilmiş gördüğüm tek Java JRE paketleri Swing'den. Genellikle, java.io.File gibi diğer sınıfları genişletmek kötü bir fikirdir, çünkü işlerin beklenmedik şekillerde hareket etmesine neden olma olasılığı vardır.
Eddie

1

Commons IO ve <Java SE 7 olmadan

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

Dosyalar file.delete () kullanılarak kolayca silinebilse de, dizinlerin silinmesi için boş olması gerekir. Bunu kolayca yapmak için özyineleme kullanın. Örneğin:

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

daha güvenli kullanım için 3 güvenlik kriteri olan bu rutini kodladım.

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

Bir örnek alalım,

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

Daha fazla bilgi için aşağıdaki kaynaklara bakın

Dizini sil


0

rm -rfoldu çok daha daha fazla ölçülebilir FileUtils.deleteDirectory.

Kapsamlı kıyaslamadan sonra, kullanımın kullanmaktan rm -rfçok daha hızlı olduğunu gördükFileUtils.deleteDirectory .

Tabii ki, küçük veya basit bir dizininiz varsa, önemli değil, ancak bizim durumumuzda birden fazla gigabayt ve 10 dakikadan fazla sürecek derin iç içe alt dizinlerimiz vardı. FileUtils.deleteDirectory ve sadece 1 dakika vardı.rm -rf .

İşte bunu yapmak için kaba Java uygulaması:

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

}

Büyük veya karmaşık dizinlerle uğraşıyorsanız denemeye değer.


Bu çapraz platform çalışıyor ??
OneCricketeer

@ cricket_007 Hangi platformlar?
Joshua Pinter

Pencereler? OpenWrt? BSD?
OneCricketeer

1
@ cricket_007 Kesinlikle Windows değil. Bu test edildi ve Android ve macOS'ta kullanıldı.
Joshua Pinter

0

Guava tek kılıfı sağlamaktadır: MoreFiles.deleteRecursively().

Paylaşılan örneklerin çoğundan farklı olarak, sembolik bağlantıları açıklar ve sağlanan yolun dışındaki dosyaları (varsayılan olarak) silmez.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.