Hapus direktori secara rekursif di Jawa


382

Apakah ada cara untuk menghapus seluruh direktori secara rekursif di Jawa?

Dalam kasus normal, dimungkinkan untuk menghapus direktori kosong. Namun ketika datang untuk menghapus seluruh direktori dengan konten, tidak sesederhana itu lagi.

Bagaimana Anda menghapus seluruh direktori dengan konten di Jawa?


4
File.delete () seharusnya mengembalikan false saat memanggilnya dengan direktori yang tidak kosong.
Ben S

Jika Anda menggunakan Java 8, lihat jawaban @ RoK.
Robin

Jawaban:


462

Anda harus memeriksa commons-io Apache . Ini memiliki kelas FileUtils yang akan melakukan apa yang Anda inginkan.

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

3
Fungsi ini mungkin membungkus kode yang disediakan erickson dalam jawabannya.
paweloque

14
Ini sedikit lebih teliti. Ini menangani hal-hal seperti tautan simbolik dengan benar di Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Steve K



Mengapa menambahkan ketergantungan lain ketika Java memiliki fasilitas di luar kotak? Lihat jawaban oleh RoK di halaman ini, atau stackoverflow.com/questions/35988192/…
foo

190

Dengan Java 7, kita akhirnya bisa melakukan ini dengan deteksi symlink yang andal. (Saya tidak menganggap Apache commons-io memiliki deteksi symlink yang andal saat ini, karena tidak menangani tautan pada Windows yang dibuat dengan mklink.)

Demi sejarah, inilah jawaban pra-Java 7, yang mengikuti symlink.

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 () tidak memiliki fungsi itu.
Ben S

14
@Erickson: Bukankah FileNotFoundException bukan pengecualian yang buruk untuk kegagalan penghapusan? Jika file tersebut benar-benar sudah tidak ada lagi, pasti sudah dihapus, yang berarti, semantik, penghapusan tidak gagal - tidak ada hubungannya. Dan jika gagal karena alasan lain, itu bukan karena file tidak ditemukan.
Lawrence Dol

46
Jadilah SANGAT HATI-HATI . Ini akan menghubungkan symlink. Jika Anda menggunakan mis. Linux, dan memiliki folder foodengan tautan foo/linksedemikian rupa link->/, panggilan delete(new File(foo)) akan menghapus sebanyak mungkin sistem file Anda seperti yang diizinkan oleh pengguna !!
Miquel

4
@Miquel Itu tidak masuk akal - Mengapa kita ingin berhati-hati? Tentunya titik kode yang disediakan adalah untuk menghapus seluruh direktori, yang memang harus dilakukan. Saya tidak mengerti apa bahayanya di sini.
Joehot200

12
@ Joehot200 Anda benar, memanggil delete pada direktori symlink tidak akan menghapus direktori, hanya symlink itu sendiri. Menghapus direktori sebenarnya perlu mengikuti symlink secara eksplisit menggunakan ReadSymbolicLink . Salahku! Terlihat dengan baik
Miquel

148

Di Java 7+ Anda bisa menggunakan Fileskelas. Kode sangat sederhana:

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
Solusi ini tampaknya sangat elegan dan tidak mengandung logika direktori traversal sama sekali!
Zero3

1
"Untuk menemukan mutiara menyelam jauh ke laut." Sejauh ini, ini adalah solusi paling rapi yang saya temukan. Harus menyelam dalam-dalam untuk menemukannya. Cemerlang!
Basil Musa

20
"Kode adalah" BUKAN "sangat sederhana" hanya menghapus dir :-) Tapi hei itu solusi terbaik di java murni kurasa.
Mat

1
Harap perhatikan bahwa kelebihan walkFileTree yang digunakan di sini " tidak mengikuti tautan simbolis ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan

1
Anda mungkin harus memanggil metode super.postVisitDirectory(dir, exc);Anda postVisitDirectory, untuk meledakkan jika jalan tidak bisa daftar direktori.
Tom Anderson

68

One-liner solution (Java8) untuk menghapus semua file dan direktori secara rekursif termasuk direktori awal:

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

Kami menggunakan pembanding untuk pesanan terbalik, jika File :: delete tidak akan dapat menghapus direktori yang mungkin tidak kosong. Jadi, jika Anda ingin menyimpan direktori dan hanya menghapus file, cukup hapus komparatornya diurutkan () atau hapus pengurutan sepenuhnya dan tambahkan filter file:

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

1
Anda perlu mengubah jenis di yang pertama menjadi .sorted (Comparator :: reverseOrder) untuk menghapus semua direktori. Kalau tidak, direktori induk dipesan sebelum anak, dan karenanya tidak akan dihapus karena tidak kosong. Jawaban yang bagus untuk mereka yang menggunakan Java 8!
Robin

1
Cara yang benar adalah .sorted(Comparator.reverseOrder())Saran Comparator::reverseOrderyang tidak bekerja. Lihat: stackoverflow.com/questions/43036611/…
user1156544

4
Robin, perhatikan tanda minus pada "-o1.compareTo (o2)". Ini sama dengan .sorted (Comparator.reverseOrder)
RoK

Apakah Files.walk berurutan? Atau apakah jawaban ini perlu untukEachOrdered alih-alih forEach untuk menghindari mencoba menghapus direktori yang tidak kosong?
Silwing

Cukup gunakan .sorted((f1, f2) -> f2.compareTo(f1)):, bandingkan f2dengan f1alih - alih f1dengan f2.
Beto Neto

67

Java 7 menambahkan dukungan untuk direktori berjalan dengan penanganan symlink:

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

Saya menggunakan ini sebagai fallback dari metode khusus platform (dalam kode yang belum diuji ):

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 dari Apache Commons Lang . Proses bersifat pribadi tetapi perilakunya harus jelas.)


Saya menemukan satu masalah dengan Files.walkFileTree - tidak cukup untuk menerapkan versi penghapusan rekursif di mana Anda terus menghapus file sampai Anda kehabisan opsi. Ini memadai untuk versi gagal-cepat, tetapi gagal-cepat tidak selalu seperti yang Anda inginkan (misalnya jika Anda membersihkan file temp, Anda ingin menghapus-sekarang, bukan gagal-cepat.)
Trejkaz

Saya tidak mengerti mengapa itu benar. Anda dapat menangani kesalahan sesuka Anda - Anda tidak diharuskan untuk gagal dengan cepat. Satu-satunya masalah yang dapat saya perkirakan adalah bahwa ia mungkin tidak menangani file baru yang dibuat selama direktori berjalan saat ini, tetapi itu adalah situasi unik yang lebih cocok untuk solusi kustom.
Trevor Robinson

1
Jika Anda menekan kesalahan dari visitFile dan memanggil walkFileTree pada satu file yang gagal, Anda tidak mendapatkan kesalahan (jadi visitFile harus menyebarkan kesalahan yang terjadi.) Jika Anda menghapus direktori dan gagal menghapus satu file, satu-satunya panggilan balik yang dipanggil adalah postVisitDirectory. yaitu, itu tidak mengunjungi file lain di direktori jika Anda mendapatkan kesalahan saat mengunjungi satu file. Ini yang saya maksud. Saya yakin mungkin ada beberapa cara untuk mengatasi ini, tetapi pada saat kami sampai pada titik ini kami telah menulis lebih banyak kode daripada rutin menghapus rekursif tradisional, jadi kami memutuskan untuk tidak menggunakannya.
Trejkaz

Terima kasih untuk kode 1 Anda, ini berguna bagi saya, tetapi saya harus mengubahnya, karena tidak menyelesaikan deltree sederhana: Saya harus mengabaikan pengecualian dalam "postVisitDirectory" dan mengembalikan LANJUTKAN terlepas karena pohon sederhana berikut tidak dapat sepenuhnya dihapus: Direktori di mana ada direktori lain di dalamnya adalah satu file. Semua yang sesederhana / normal, pada Windows.
Dreamspace President

Semuanya berawal dari java.nio.file.DirectoryNotEmptyException yang saya dapat. Saya menemukan kasus di mana visitFileFailed digunakan. Jika struktur direktori Anda memiliki tautan tipe persimpangan di windows. Ini dapat menyebabkan Anda 2 masalah: *) Files.walkFileTree mengikuti tautan ke persimpangan dan menghapus semua yang ada di sana. *) Jika direktori target persimpangan sudah dihapus maka parsing tautan oleh Files.walkFileTree gagal dengan NoSuchFileException yang ditangkap di visitFileFailed.
Andres Luuk

34

Hanya melihat solusi saya kurang lebih sama dengan erickson, hanya dikemas sebagai metode statis. Jatuhkan ini di suatu tempat, ini jauh lebih ringan daripada menginstal semua Apache Commons untuk sesuatu yang (seperti yang Anda lihat) cukup sederhana.

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

Solusi dengan tumpukan dan tanpa metode rekursif:

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 untuk menggunakan tumpukan. Ini akan bekerja dengan direktori yang berisi subdirektori bertingkat tingkat tinggi sementara pendekatan berbasis tumpukan lainnya akan gagal.
Nathan Osman

4
Melihat bahwa Anda biasanya tidak memiliki masalah bersarang beberapa ratus panggilan metode saya pikir Anda cenderung mengalami pembatasan filesystem jauh sebelumnya.
Bombe

2
Hati-hati dengan list*metode untuk kelas java.io.File. Dari Javadocs: "Mengembalikan nol jika pathname abstrak ini tidak menunjukkan direktori, atau jika kesalahan I / O terjadi." Jadi: if (currList.length > 0) {menjadiif (null != currList && currList.length > 0) {
kevinarpe

1
Saya menggunakan ArrayDeque bukan Stack yang sedikit lebih cepat. (tidak disinkronkan)
Wytze


15

Jambu telah Files.deleteRecursively(File)mendukung sampai Jambu 9 .

Dari Jambu 10 :

Usang. Metode ini menderita deteksi symlink dan kondisi ras yang buruk. Fungsionalitas ini dapat didukung hanya dengan keluar ke perintah sistem operasi seperti rm -rfatau del /s. Metode ini dijadwalkan akan dihapus dari Jambu di rilis Jambu 11.0.

Oleh karena itu, tidak ada metode seperti itu di Jambu Biji 11 .


6
Sangat buruk. Keluar sepertinya agak kasar dan tidak portabel. Jika versi Apache commons berfungsi dengan baik, maka mungkin itu bukan tidak mungkin untuk diterapkan.
Andrew McKinlay

6
@andrew Implementasi Apache Commons seharusnya memiliki masalah yang sama dengan yang menyebabkan Guava menghapus implementasinya, lihat code.google.com/p/guava-libraries/issues/detail?id=365
orip

Versi apache commons mendeteksi symlink, dan sama sekali tidak melintasi anak-anak file.
Ajax

5
Guava 21.0 menambahkan ini sebagai MoreFiles.deleteRecursively () .
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);
}

Atau jika Anda ingin menangani IOException:

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

2
Ini membantu saya menghasilkan versi Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward

Apakah memilah benar-benar diperlukan? The walkMetode sudah menjamin traversal depth-first.
VGR

Komparator dapat didaur ulang dari Collections.reverseOrder()sehingga kode Anda akan for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))menganggap itu telah diimpor secara statis.
namero999

@ namero999 Maksud Anda Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff

@ Jeff cukup yakin Anda benar, sebagian besar berlalu ingatan di sana :)
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
Versi yang disempurnakan dengan nilai pengembalian boolean dan tanpa duplikasi: 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();
    }
}

Kode yang bagus, tetapi ada satu bug, ketika diperbaiki, ia berfungsi. Baris di f.delete()bawah deleteDirectory(f)akan melempar NoSuchFileException karena deleteDirectory(f)sudah menghapus file itu. Setiap direktori akan menjadi jalur ketika dilewatkan deleteDirectory(f)dan dihapus oleh path.delete(). Karena itu, kita tidak perlu f.delete()di if f.isDerectorybagian. Jadi, hapus saja di f.delete();bawah deleteDirectory (f) dan itu akan berfungsi.
Trieu Nguyen

5

Dua cara untuk gagal dengan symlink dan kode di atas ... dan tidak tahu solusinya.

Cara # 1

Jalankan ini untuk membuat tes:

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

Di sini Anda melihat file pengujian dan direktori pengujian Anda:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Kemudian jalankan deleteDirectory () commons-io Anda. Itu crash mengatakan file tidak ditemukan. Tidak yakin apa yang dilakukan contoh lain di sini. Perintah Linux rm hanya akan menghapus tautan, dan rm -r pada direktori juga akan.

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

Cara # 2

Jalankan ini untuk membuat tes:

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

Di sini Anda melihat file pengujian dan direktori pengujian Anda:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Kemudian jalankan commons-io deleteDirectory () atau kode contoh yang diposkan orang. Itu menghapus tidak hanya direktori, tetapi testfile Anda yang berada di luar direktori sedang dihapus. (Ini menyangkal direktori secara implisit, dan menghapus konten). rm -r hanya akan menghapus tautan. Anda perlu menggunakan sesuatu seperti ini untuk menghapus file-file yang direferensikan: "find -L dirtodelete -type f -exec rm {} \;".

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

4

Anda bisa menggunakan:

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

Menghapus file, tidak pernah melempar pengecualian. Jika file adalah direktori, hapus dan semua sub-direktori. Perbedaan antara File.delete () dan metode ini adalah: Direktori yang akan dihapus tidak harus kosong. Tidak ada pengecualian yang dilemparkan ketika file atau direktori tidak dapat dihapus.


4

Solusi optimal yang menangani pengecualian secara konsisten dengan pendekatan yang dilemparkan oleh pengecualian dari suatu metode harus selalu menggambarkan apa yang coba dilakukan oleh metode tersebut (dan gagal):

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

Dalam proyek lawas, saya perlu membuat kode Java asli. Saya membuat kode ini mirip dengan kode Paulitex. Lihat itu:

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

Dan unit test:

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

Kode di bawah ini secara rekursif menghapus semua konten dalam folder yang diberikan.

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

2

Berikut ini adalah metode utama tulang kosong yang menerima argumen baris perintah, Anda mungkin perlu menambahkan kesalahan Anda sendiri memeriksa atau membentuknya sesuai keinginan Anda.

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

Saya harap itu membantu!


1

Mungkin solusi untuk masalah ini mungkin menerapkan kembali metode penghapusan kelas File menggunakan kode dari jawaban 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
Saya pikir ini diterapkan karena meniru perilaku sebagian besar utilitas shell perintah seperti "rm", "rmdir", dan "del". Dari dua alternatif tersebut, implementasi saat ini pasti meminimalkan potensi kejutan (dan kemarahan) keseluruhan. Itu tidak akan berubah.
erickson

4
Secara umum, satu-satunya paket Java JRE yang saya lihat diperluas berasal dari Swing. Biasanya, memperluas kelas lain seperti java.io.File adalah ide yang buruk, karena memiliki kemungkinan untuk menyebabkan sesuatu bertindak dengan cara yang tidak terduga.
Eddie

1

Tanpa Commons IO dan <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

Sementara file dapat dengan mudah dihapus menggunakan file.delete (), direktori diharuskan kosong untuk dihapus. Gunakan rekursi untuk melakukan ini dengan mudah. Sebagai contoh:

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

saya mengkodekan rutin ini yang memiliki 3 kriteria keselamatan untuk penggunaan yang lebih aman.

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

Nah, mari kita ambil contoh,

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

Untuk informasi lebih lanjut, lihat sumber daya di bawah ini

Hapus direktori


0

rm -rfitu jauh lebih performant dariFileUtils.deleteDirectory .

Setelah melakukan tolok ukur yang luas, kami menemukan bahwa menggunakan rm -rfbeberapa kali lebih cepat daripada menggunakanFileUtils.deleteDirectory .

Tentu saja, jika Anda memiliki direktori kecil atau sederhana, itu tidak masalah, tetapi dalam kasus kami, kami memiliki beberapa gigabyte dan sub direktori yang sangat bersarang di mana itu akan memakan waktu lebih dari 10 menit FileUtils.deleteDirectorydan hanya 1 menit rm -rf.

Inilah implementasi Java kami yang kasar untuk melakukan itu:

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

}

Pantas untuk dicoba jika Anda berurusan dengan direktori besar atau kompleks.


Ini bekerja crossp-platform ??
OneCricketeer

@ cricket_007 Platform apa?
Joshua Pinter

Windows? OpenWrt? BSD?
OneCricketeer

1
@ cricket_007 Jelas bukan Windows. Ini diuji dan digunakan pada Android dan macOS.
Joshua Pinter

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.