Bagaimana cara menghapus seluruh folder dan konten?

187

Saya ingin pengguna aplikasi saya dapat menghapus folder DCIM (yang terletak di kartu SD dan berisi subfolder).

Apakah ini mungkin, jika demikian, bagaimana?

Pemula
sumber
1
selain pendekatan penghapusan bottom-up rekursif?
Sarwar Erfan
Jika Anda memiliki direktori yang sangat besar atau kompleks Anda harus menggunakan rm -rf directorybukan FileUtils.deleteDirectory. Setelah melakukan pembandingan, kami menemukan beberapa kali lebih cepat. Lihat contoh implementasi di sini: stackoverflow.com/a/58421350/293280
Joshua Pinter

Jawaban:

301

Biarkan saya memberi tahu Anda hal pertama yang Anda tidak dapat menghapus folder DCIM karena itu adalah folder sistem. Ketika Anda menghapusnya secara manual di telepon, ia akan menghapus isi folder itu, tetapi bukan folder DCIM. Anda dapat menghapus kontennya dengan menggunakan metode di bawah ini:

Diperbarui sesuai komentar

File dir = new File(Environment.getExternalStorageDirectory()+"Dir_name_here"); 
if (dir.isDirectory()) 
{
    String[] children = dir.list();
    for (int i = 0; i < children.length; i++)
    {
       new File(dir, children[i]).delete();
    }
}
chikka.anddev
sumber
3
erm bagaimana cara saya menyatakan dir?
Pemula
Saya pada dasarnya mencoba untuk menghapus semua foto sehingga tidak masalah adalah DCIM tidak dihapus selama foto-foto ... jadi bahkan menghapus 100MEDIA folder dalam ini akan melakukan pekerjaan
Pemula
1
Anda harus mendeklarasikan direktori dengan menggunakan path folder dicm: use file r = file (path);
chikka.anddev
3
menggunakan File dir = File baru (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Pemula
1
@chiragshah Setelah Menghapus folder dan membuat ulang folder yang menghasilkan pembuatan file yang tidak dikenal dengan nama folder yang sama disebutkan. Dan jika saya mencoba mengakses file itu melempar pengecualian seperti Resource atau perangkat sibuk. Saya juga memeriksa Properti dari file di mana saya menemukan MD5 Signature: Operation Failure
sha
529

Anda dapat menghapus file dan folder secara rekursif seperti ini:

void deleteRecursive(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory())
        for (File child : fileOrDirectory.listFiles())
            deleteRecursive(child);

    fileOrDirectory.delete();
}
Teedyay
sumber
21
Saya tidak melakukan tes untuk efisiensi, tetapi saya percaya tes saya lebih kuat. chirag akan berfungsi untuk kasus spesifik folder DCIM, di mana folder dalam DCIM hanya boleh berisi file (yaitu folder di dalam DCIM biasanya tidak berisi subfolder). Versi saya akan menghapus folder yang bersarang sampai kedalaman berapa pun. Ada kemungkinan bahwa pengguna telah mengubah konten kartu SD-nya sehingga DCIM berisi folder yang bersarang lebih dalam (misalnya DCIM\foo\bar\pic.jpg), dalam hal ini kode chirag akan gagal.
teedyay
2
Sebuah pertanyaan yang ditanyakan oleh seorang rekan kerja kepada saya: Apa yang terjadi jika sebuah folder memiliki tautan simbolis pada dirinya sendiri dan Anda menjalankan potongan kode ini?
p4u144
1
@ p4u144 Beri kolega Anda nilai tertinggi untuk menjadi jenius! Terlihat dengan baik! Sejujurnya saya tidak tahu apakah kode ini akan menghormati dan mengikuti tautan simbolik, tetapi jika ya, Anda akan memiliki loop tak terbatas. Apakah Anda suka mengujinya?
teedyay
8
@ p4u144 Jangan khawatir tentang tautan simbolik. "Dengan tautan simbolik, tautan dihapus dan bukan target tautan." dari docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin
3
Ada kemungkinan NPE di sini: fileOrDirectory.listFiles()dapat kembali nulljika ada kesalahan I / O saat membaca file. Ini dinyatakan dengan jelas dalam dokumentasi: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho
67

Kita bisa menggunakan argumen baris perintah untuk menghapus seluruh folder dan isinya.

public static void deleteFiles(String path) {

    File file = new File(path);

    if (file.exists()) {
        String deleteCmd = "rm -r " + path;
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec(deleteCmd);
        } catch (IOException e) { }
    }
}

Contoh penggunaan kode di atas:

deleteFiles("/sdcard/uploads/");
xinaxino
sumber
2
sepertinya bagus, apakah Anda tahu apakah ini sinkron atau asinkron? Dokumentasi tidak mengatakan: developer.android.com/reference/java/lang/…
Seseorang di suatu tempat
2
Ide buruk. Mengapa melakukannya di shell?
noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
sudocoder
34

Di Kotlin Anda dapat menggunakan deleteRecursively()ekstensi dari kotlin.iopaket

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Dima Rostopira
sumber
2
Di Jawa, Anda dapat menggunakan FilesKt.deleteRecursively(new File("/path/to/dir"));jika Anda menggunakan kotlin-stdlib
Joonsoo
Perintah ini akan menghapus direktori "/ dir" dengan konten di dalamnya atau hanya konten di dalam direktori "/ dir" dan direktori tetap ada?
Bhimbim
1
@ Bhimbim biar Google docs untuk Anda "Hapus file ini dengan semua anak-anaknya.". Jadi, direktori akan dihapus dan juga isinya
Dima Rostopira
@DimaRostopira terima kasih!
Bhimbim
kotlin untuk menyelamatkan!
Tobi Oyelekan
15

gunakan metode di bawah ini untuk menghapus seluruh direktori utama yang berisi file dan sub direktori itu. Setelah memanggil metode ini, sekali lagi panggil direktori delete () dari direktori utama Anda.

// For to Delete the directory inside list of files and inner Directory
public static boolean deleteDir(File dir) {
    if (dir.isDirectory()) {
        String[] children = dir.list();
        for (int i=0; i<children.length; i++) {
            boolean success = deleteDir(new File(dir, children[i]));
            if (!success) {
                return false;
            }
        }
    }

    // The directory is now empty so delete it
    return dir.delete();
}
Android
sumber
Dari semua jawaban, ini adalah jawaban nyata SAJA yang menghapus direktori juga setelah menghapus file di dalamnya.
zeeshan
File file = File baru (Environment.getExternalStorageDirectory () + separator + "folder_name" + separator); deleteDir (file); Ya ini berfungsi. Terima kasih :)
ashishdhiman2007
14

Pendekatan Anda layak untuk folder yang hanya berisi file, tetapi jika Anda mencari skenario yang juga berisi subfolder maka rekursi diperlukan

Anda juga harus menangkap nilai pengembalian untuk memastikan Anda diizinkan menghapus file

dan termasuk

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

dalam manifes Anda

void DeleteRecursive(File dir)
{
    Log.d("DeleteRecursive", "DELETEPREVIOUS TOP" + dir.getPath());
    if (dir.isDirectory())
    {
        String[] children = dir.list();
        for (int i = 0; i < children.length; i++)
        {
            File temp = new File(dir, children[i]);
            if (temp.isDirectory())
            {
                Log.d("DeleteRecursive", "Recursive Call" + temp.getPath());
                DeleteRecursive(temp);
            }
            else
            {
                Log.d("DeleteRecursive", "Delete File" + temp.getPath());
                boolean b = temp.delete();
                if (b == false)
                {
                    Log.d("DeleteRecursive", "DELETE FAIL");
                }
            }
        }

    }
    dir.delete();
}
GregM
sumber
5
Ini mungkin lebih mudah jika Anda gunakan untuk (File currentFile: file.listFiles ()) {
Thorben
8

Ada banyak jawaban, tetapi saya memutuskan untuk menambahkan jawaban saya sendiri, karena sedikit berbeda. Ini didasarkan pada OOP;)

Saya membuat class DirectoryCleaner , yang membantu saya setiap kali ketika saya perlu membersihkan beberapa direktori.

public class DirectoryCleaner {
    private final File mFile;

    public DirectoryCleaner(File file) {
        mFile = file;
    }

    public void clean() {
        if (null == mFile || !mFile.exists() || !mFile.isDirectory()) return;
        for (File file : mFile.listFiles()) {
            delete(file);
        }
    }

    private void delete(File file) {
        if (file.isDirectory()) {
            for (File child : file.listFiles()) {
                delete(child);
            }
        }
        file.delete();

    }
}

Ini dapat digunakan untuk menyelesaikan masalah ini dengan cara berikut:

File dir = new File(Environment.getExternalStorageDirectory(), "your_directory_name");
new DirectoryCleaner(dir).clean();
dir.delete();
gio
sumber
7

Jika Anda tidak perlu menghapus hal-hal secara rekursif Anda dapat mencoba sesuatu seperti ini:

File file = new File(context.getExternalFilesDir(null), "");
    if (file != null && file.isDirectory()) {
        File[] files = file.listFiles();
        if(files != null) {
            for(File f : files) {   
                f.delete();
            }
        }
    }
Marty
sumber
6

Anda tidak dapat menghapus direktori jika memiliki subdirektori atau file di Java. Coba solusi sederhana dua baris ini. Ini akan menghapus direktori dan kontes di dalam direktori.

File dirName = new File("directory path");
FileUtils.deleteDirectory(dirName);

Tambahkan baris ini dalam file gradle dan sinkronkan proyek

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A
sumber
Sebagai 2 liner, sederhana. Tetapi menginstal seluruh perpustakaan untuk memanfaatkan hanya salah satu metodenya tampaknya tidak efisien. Gunakan ini sebagai gantinya
Kathir
ujung insert gradle menyelamatkan hidupku.
Dracarys
5
public static void deleteDirectory( File dir )
{

    if ( dir.isDirectory() )
    {
        String [] children = dir.list();
        for ( int i = 0 ; i < children.length ; i ++ )
        {
         File child =    new File( dir , children[i] );
         if(child.isDirectory()){
             deleteDirectory( child );
             child.delete();
         }else{
             child.delete();

         }
        }
        dir.delete();
    }
}
Verma yang dalam
sumber
4

Menurut dokumentasi :

Jika pathname abstrak ini tidak menunjukkan direktori, maka metode ini mengembalikan nol.

Jadi, Anda harus memeriksa apakah listFilesini nulldan hanya melanjutkan jika itu tidak

boolean deleteDirectory(File path) {
    if(path.exists()) {
        File[] files = path.listFiles();
        if (files == null) {
            return false;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                deleteDirectory(file);
            } else {
                boolean wasSuccessful = file.delete();
                if (wasSuccessful) {
                    Log.i("Deleted ", "successfully");
                }
            }
        }
    }
    return(path.delete());
}
HB.
sumber
1
Ini harus menjadi jawaban yang diterima. Bekerja seperti pesona!
MSeiz5
3

Inilah yang saya lakukan ... (singkat dan teruji)

    ...
    deleteDir(new File(dir_to_be_deleted));
    ...

    // delete directory and contents
    void deleteDir(File file) { 
        if (file.isDirectory())
            for (String child : file.list())
                deleteDir(new File(file, child));
        file.delete();  // delete child file or empty directory
    }
SoloPilot
sumber
3
private static void deleteRecursive(File dir)
{
    //Log.d("DeleteRecursive", "DELETEPREVIOUS TOP" + dir.getPath());
    if (dir.isDirectory())
    {
        String[] children = dir.list();
        for (int i = 0; i < children.length; i++)
        {
            File temp = new File(dir, children[i]);
            deleteRecursive(temp);
        }

    }

    if (dir.delete() == false)
    {
        Log.d("DeleteRecursive", "DELETE FAIL");
    }
}
JasonCheung
sumber
2

Cara mudah untuk menghapus semua file dari direktori:

Ini adalah fungsi umum untuk menghapus semua gambar dari direktori dengan memanggil saja

deleteAllImageFile (konteks);

public static void deleteAllFile(Context context) {
File directory = context.getExternalFilesDir(null);
        if (directory.isDirectory()) {
            for (String fileName: file.list()) {
                new File(file,fileName).delete();
            }
        }    
    } 
Sagar Chorage
sumber
2

Kode teraman yang saya tahu:

private boolean recursiveRemove(File file) {
    if(file == null  || !file.exists()) {
        return false;
    }

    if(file.isDirectory()) {
        File[] list = file.listFiles();

        if(list != null) {

            for(File item : list) {
                recursiveRemove(item);
            }

        }
    }

    if(file.exists()) {
        file.delete();
    }

    return !file.exists();
}

Memeriksa file yang ada, menangani nulls, memeriksa direktori yang sebenarnya dihapus

Gary Davies
sumber
2

Versi koltin pendek

fun File.deleteDirectory(): Boolean {
    return if (exists()) {
        listFiles()?.forEach {
            if (it.isDirectory) {
                it.deleteDirectory()
            } else {
                it.delete()
            }
        }
        delete()
    } else false
}
Vlad
sumber
1

Berikut ini adalah implementasi non-rekursif, hanya untuk bersenang-senang:

/**
 * Deletes the given folder and all its files / subfolders.
 * Is not implemented in a recursive way. The "Recursively" in the name stems from the filesystem command
 * @param root The folder to delete recursively
 */
public static void deleteRecursively(final File root) {
    LinkedList<File> deletionQueue = new LinkedList<>();
    deletionQueue.add(root);

    while(!deletionQueue.isEmpty()) {
        final File toDelete = deletionQueue.removeFirst();
        final File[] children = toDelete.listFiles();
        if(children == null || children.length == 0) {
            // This is either a file or an empty directory -> deletion possible
            toDelete.delete();
        } else {
            // Add the children before the folder because they have to be deleted first
            deletionQueue.addAll(Arrays.asList(children));
            // Add the folder again because we can't delete it yet.
            deletionQueue.addLast(toDelete);
        }
    }
}
PhilLab
sumber
1

Ini (Mencoba menghapus semua sub-file dan sub-direktori termasuk direktori yang disediakan) :

  1. Jika File, hapus
  2. Jika Empty Directory, hapus
  3. jika Not Empty Directory, panggil hapus lagi dengan sub-direktori, ulangi 1 hingga 3

contoh:

File externalDir = Environment.getExternalStorageDirectory()
Utils.deleteAll(externalDir); //BE CAREFUL.. Will try and delete ALL external storage files and directories

Untuk mendapatkan akses ke Direktori Penyimpanan Eksternal, Anda memerlukan izin berikut:

(Gunakan ContextCompat.checkSelfPermissiondan ActivityCompat.requestPermissions)

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Metode rekursif:

public static boolean deleteAll(File file) {
    if (file == null || !file.exists()) return false;

    boolean success = true;
    if (file.isDirectory()) {
        File[] files = file.listFiles();
        if (files != null && files.length > 0) {
            for (File f : files) {
                if (f.isDirectory()) {
                    success &= deleteAll(f);
                }
                if (!f.delete()) {
                    Log.w("deleteAll", "Failed to delete " + f);
                    success = false;
                }
            }
        } else {
            if (!file.delete()) {
                Log.w("deleteAll", "Failed to delete " + file);
                success = false;
            }
        }
    } else {
        if (!file.delete()) {
            Log.w("deleteAll", "Failed to delete " + file);
            success = false;
        }
    }
    return success;
}
Pierre
sumber
0

Saya telah menempatkan ini meskipun langkahnya menghapus folder dengan struktur direktori apa pun.

public int removeDirectory(final File folder) {

    if(folder.isDirectory() == true) {
        File[] folderContents = folder.listFiles();
        int deletedFiles = 0;

        if(folderContents.length == 0) {
            if(folder.delete()) {
                deletedFiles++;
                return deletedFiles;
            }
        }
        else if(folderContents.length > 0) {

            do {

                File lastFolder = folder;
                File[] lastFolderContents = lastFolder.listFiles();

                //This while loop finds the deepest path that does not contain any other folders
                do {

                    for(File file : lastFolderContents) {

                        if(file.isDirectory()) {
                            lastFolder = file;
                            lastFolderContents = file.listFiles();
                            break;
                        }
                        else {

                            if(file.delete()) {
                                deletedFiles++;
                            }
                            else {
                                break;
                            }

                        }//End if(file.isDirectory())

                    }//End for(File file : folderContents)

                } while(lastFolder.delete() == false);

                deletedFiles++;
                if(folder.exists() == false) {return deletedFiles;}

            } while(folder.exists());
        }
    }
    else {
        return -1;
    }

    return 0;

}

Semoga ini membantu.

pengguna2288580
sumber
0
//To delete all the files of a specific folder & subfolder
public static void deleteFiles(File directory, Context c) {
    try {
        for (File file : directory.listFiles()) {
            if (file.isFile()) {
                final ContentResolver contentResolver = c.getContentResolver();
                String canonicalPath;
                try {
                    canonicalPath = file.getCanonicalPath();
                } catch (IOException e) {
                    canonicalPath = file.getAbsolutePath();
                }
                final Uri uri = MediaStore.Files.getContentUri("external");
                final int result = contentResolver.delete(uri,
                        MediaStore.Files.FileColumns.DATA + "=?", new String[]{canonicalPath});
                if (result == 0) {
                    final String absolutePath = file.getAbsolutePath();
                    if (!absolutePath.equals(canonicalPath)) {
                        contentResolver.delete(uri,
                                MediaStore.Files.FileColumns.DATA + "=?", new String[]{absolutePath});
                    }
                }
                if (file.exists()) {
                    file.delete();
                    if (file.exists()) {
                        try {
                            file.getCanonicalFile().delete();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        if (file.exists()) {
                            c.deleteFile(file.getName());
                        }
                    }
                }
            } else
                deleteFiles(file, c);
        }
    } catch (Exception e) {
    }
}

di sini adalah solusi Anda juga akan menyegarkan galeri juga.

Bilal Mustafa
sumber
0

Namun cara (modern) lain untuk menyelesaikannya.

public class FileUtils {
    public static void delete(File fileOrDirectory) {
        if(fileOrDirectory != null && fileOrDirectory.exists()) {
            if(fileOrDirectory.isDirectory() && fileOrDirectory.listFiles() != null) {      
                Arrays.stream(fileOrDirectory.listFiles())
                      .forEach(FileUtils::delete);
            }
            fileOrDirectory.delete();
        }
    }
}

Di Android sejak API 26

public class FileUtils {

    public static void delete(File fileOrDirectory)  {
        if(fileOrDirectory != null) {
            delete(fileOrDirectory.toPath());
        }
    }

    public static void delete(Path path)  {
        try {
            if(Files.exists(path)) {
                Files.walk(path)
                        .sorted(Comparator.reverseOrder())
                        .map(Path::toFile)
//                      .peek(System.out::println)
                        .forEach(File::delete);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Ch4rl3x
sumber
0

Saya menggunakan fungsi rekursif ini untuk melakukan pekerjaan:

public static void deleteDirAndContents(@NonNull File mFile){
    if (mFile.isDirectory() && mFile.listFiles() != null && mFile.listFiles().length > 0x0) {
        for (File file : mFile.listFiles()) {
            deleteDirAndContents(file);
        }
    } else {
        mFile.delete();
    }
}

Fungsi memeriksa apakah itu adalah direktori atau file.

Jika sebuah direktori memeriksa apakah ia memiliki file anak, jika memiliki file anak, akan memanggil dirinya sendiri untuk meneruskan anak-anak dan mengulanginya.

Jika itu file, hapus saja.

(Jangan gunakan fungsi ini untuk menghapus cache aplikasi dengan mengirimkan direktori cache karena itu akan menghapus direktori cache juga sehingga aplikasi akan macet ... Jika Anda ingin menghapus cache Anda menggunakan fungsi ini yang tidak akan menghapus dir Anda lolos:

public static void deleteDirContents(@NonNull File mFile){
        if (mFile.isDirectory() && mFile.listFiles() != null && mFile.listFiles().length > 0x0) {
            for (File file : mFile.listFiles()) {
                deleteDirAndContents(file);
            }
        }
    }

atau Anda dapat memeriksa apakah itu cache dir menggunakan:

if (!mFile.getAbsolutePath().equals(context.getCacheDir().getAbsolutePath())) {
    mFile.delete();
}

Kode contoh untuk menghapus cache aplikasi:

public static void clearAppCache(Context context){
        try {
            File cache = context.getCacheDir();
            FilesUtils.deleteDirContents(cache);
        } catch (Exception e){
            MyLogger.onException(TAG, e);
        }
    }

Sampai jumpa, Semoga harimu menyenangkan & coding: D

Z3R0
sumber