Wie lösche ich einen ganzen Ordner und Inhalt?

185

Ich möchte, dass die Benutzer meiner Anwendung den DCIM-Ordner löschen können (der sich auf der SD-Karte befindet und Unterordner enthält).

Ist das möglich, wenn ja wie?

Anfänger
quelle
1
anders als rekursiver Bottom-up-Löschansatz?
Sarwar Erfan
Wenn Sie ein sehr großes oder komplexes Verzeichnis haben, sollten Sie rm -rf directorystattdessen verwenden FileUtils.deleteDirectory. Nach dem Benchmarking stellten wir fest, dass es um ein Vielfaches schneller war. Schauen Sie sich hier eine Beispielimplementierung an: stackoverflow.com/a/58421350/293280
Joshua Pinter

Antworten:

299

Lassen Sie mich zunächst sagen, dass Sie den DCIM-Ordner nicht löschen können, da es sich um einen Systemordner handelt. Wenn Sie es manuell auf dem Telefon löschen, wird der Inhalt dieses Ordners gelöscht, nicht jedoch der DCIM-Ordner. Sie können den Inhalt mithilfe der folgenden Methode löschen:

Aktualisiert gemäß Kommentar

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
quelle
3
ähm wie soll ich erklären was dir ist?
Anfänger
Ich versuche im Grunde, alle Fotos zu löschen, also spielt es keine Rolle, dass DCIM nicht gelöscht wird, solange die Fotos ... also würde selbst das Löschen von 100MEDIA den Ordner in diesem Ordner den Job machen
Anfänger
1
Sie müssen das Verzeichnis unter Verwendung des Pfads des DICM-Ordners deklarieren: Verwenden Sie die Datei r = Datei (Pfad).
chikka.anddev
3
verwendete Datei dir = neue Datei (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Anfänger
1
@chiragshah Nach dem Löschen eines Ordners und dem Neuerstellen des Ordners wird eine unbekannte Datei mit dem gleichen Namen des genannten Ordners erstellt. Und wenn ich versuche, auf diese Datei zuzugreifen, wird eine Ausnahme wie Ressource oder Gerät ausgelastet ausgelöst. Ich habe auch die Eigenschaften von überprüft Datei, in der ich MD5 Signatur gefunden habe: Operation Failure
sha
529

Sie können Dateien und Ordner rekursiv wie folgt löschen:

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

    fileOrDirectory.delete();
}
teedyay
quelle
21
Ich habe keine Effizienzprüfungen durchgeführt, aber ich glaube, meine ist robuster. chirag's funktioniert für den speziellen Fall des DCIM-Ordners, in dem Ordner in DCIM nur Dateien enthalten sollten (dh Ordner in DCIM enthalten normalerweise keine Unterordner). Meine Version löscht Ordner, die in beliebiger Tiefe verschachtelt sind. Es besteht die Möglichkeit, dass der Benutzer den Inhalt seiner SD-Karte so geändert hat, dass DCIM Ordner enthält, die tiefer verschachtelt sind (z. B. DCIM\foo\bar\pic.jpg). In diesem Fall schlägt der Code von chirag fehl.
Teedyay
2
Eine Frage, die mir ein Kollege gestellt hat: Was passiert, wenn ein Ordner einen symbolischen Link hat und Sie diesen Codeabschnitt ausführen?
p4u144
1
@ p4u144 Geben Sie Ihrem Kollegen einen High-Five, um ein Genie zu sein! Gut erkannt! Um ehrlich zu sein, weiß ich nicht, ob dieser Code symbolische Links respektieren und ihnen folgen würde, aber wenn dies der Fall ist, haben Sie eine Endlosschleife. Möchten Sie es testen?
Teedyay
8
@ p4u144 Keine Sorge um symbolische Links. "Bei symbolischen Links wird der Link gelöscht und nicht das Ziel des Links." von docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin
3
Hier gibt es eine mögliche NPE: fileOrDirectory.listFiles()Kann zurückkehren, nullwenn beim Lesen der Dateien ein E / A-Fehler auftritt. Dies ist in der Dokumentation klar angegeben: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho
67

Wir können die Befehlszeilenargumente verwenden, um einen ganzen Ordner und seinen Inhalt zu löschen.

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

Beispiel für die Verwendung des obigen Codes:

deleteFiles("/sdcard/uploads/");
Xinaxino
quelle
2
scheint gut zu sein, wissen Sie, ob dies synchron oder asynchron ist? Die Dokumentation sagt nicht: developer.android.com/reference/java/lang/…
Jemand irgendwo
2
Schlechte Idee. Warum auf der Schale?
Noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
Sudocoder
32

In Kotlin können Sie die deleteRecursively()Erweiterung aus dem kotlin.ioPaket verwenden

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Dima Rostopira
quelle
2
In Java können Sie verwenden, FilesKt.deleteRecursively(new File("/path/to/dir"));wenn Sie kotlin-stdlib
Joonsoo
Dieser Befehl löscht das Verzeichnis "/ dir" mit dem Inhalt im Verzeichnis oder nur den Inhalt im Verzeichnis "/ dir" und das Verzeichnis bleibt dort?
Bhimbim
1
@ Bhimbim lemme google docs für Sie "Löschen Sie diese Datei mit all ihren Kindern." Das Verzeichnis wird also ebenso gelöscht wie der Inhalt
Dima Rostopira
Vielen Dank, dass Sie @DimaRostopira!
Bhimbim
Kotlin zur Rettung!
Tobi Oyelekan
15

Verwenden Sie die folgende Methode, um das gesamte Hauptverzeichnis zu löschen, das Dateien und sein Unterverzeichnis enthält. Rufen Sie nach dem erneuten Aufruf dieser Methode das Verzeichnis delete () Ihres Hauptverzeichnisses auf.

// 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
quelle
Von allen Antworten ist dies die EINZIGE echte Antwort, die das Verzeichnis auch nach dem Löschen der darin enthaltenen Dateien löscht.
Zeeshan
Datei file = neue Datei (Environment.getExternalStorageDirectory () + Trennzeichen + "Ordnername" + Trennzeichen); deleteDir (Datei); Ja, das funktioniert. Danke :)
ashishdhiman2007
14

Ihr Ansatz ist für einen Ordner angemessen, der nur Dateien enthält. Wenn Sie jedoch nach einem Szenario suchen, das auch Unterordner enthält, ist eine Rekursion erforderlich

Außerdem sollten Sie den Rückgabewert der Rückgabe erfassen, um sicherzustellen, dass Sie die Datei löschen dürfen

und einschließen

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

in deinem Manifest

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
quelle
5
Dies könnte einfacher sein, wenn Sie für (Datei currentFile: file.listFiles ()) {
Thorben
8

Es gibt viele Antworten, aber ich habe beschlossen, meine eigenen hinzuzufügen, weil es wenig anders ist. Es basiert auf OOP;)

Ich habe die Klasse DirectoryCleaner erstellt , die mir jedes Mal hilft, wenn ich ein Verzeichnis bereinigen muss.

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

    }
}

Es kann verwendet werden, um dieses Problem auf folgende Weise zu lösen:

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

Wenn Sie Dinge nicht rekursiv löschen müssen, können Sie Folgendes versuchen:

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
quelle
6

Sie können das Verzeichnis nicht löschen, wenn es Unterverzeichnisse oder Dateien in Java enthält. Probieren Sie diese einfache Lösung mit zwei Zeilen aus. Dadurch werden das Verzeichnis und die Wettbewerbe innerhalb des Verzeichnisses gelöscht.

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

Fügen Sie diese Zeile in die Gradle-Datei ein und synchronisieren Sie das Projekt

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A.
quelle
Als 2-Liner ist es einfach. Die Installation einer gesamten Bibliothek zur Verwendung nur einer ihrer Methoden scheint jedoch ineffizient zu sein. Verwenden Sie dies stattdessen
Kathir
Gradle Insert Tip hat mir das Leben gerettet.
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();
    }
}
Tiefes Verma
quelle
5

siehe android.os.FileUtils, es ist auf API 21 versteckt

public static boolean deleteContents(File dir) {
    File[] files = dir.listFiles();
    boolean success = true;
    if (files != null) {
        for (File file : files) {
            if (file.isDirectory()) {
                success &= deleteContents(file);
            }
            if (!file.delete()) {
                Log.w("Failed to delete " + file);
                success = false;
            }
        }
    }
    return success;
}

Quelle: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/FileUtils.java#414

edwardaa
quelle
4

Laut Dokumentation :

Wenn dieser abstrakte Pfadname kein Verzeichnis bezeichnet, gibt diese Methode null zurück.

Sie sollten also prüfen, ob dies der Fall listFilesist, nullund nur dann fortfahren, wenn dies nicht der Fall ist

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.
quelle
1
Dies sollte die akzeptierte Antwort sein. Klappt wunderbar!
MSeiz5
3

Das mache ich ... (knapp und getestet)

    ...
    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
quelle
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
quelle
2

Einfache Möglichkeit, alle Dateien aus dem Verzeichnis zu löschen:

Es ist eine generische Funktion zum Löschen aller Bilder aus dem Verzeichnis, indem nur aufgerufen wird

deleteAllImageFile (Kontext);

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
quelle
2

Sicherster Code, den ich kenne:

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

Überprüft, ob die Datei vorhanden ist, behandelt Nullen und überprüft, ob das Verzeichnis tatsächlich gelöscht wurde

Gary Davies
quelle
1

Hier ist eine nicht rekursive Implementierung, nur zum Spaß:

/**
 * 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
quelle
1

Kurze koltin Version

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

Dies (Versucht, alle Unterdateien und Unterverzeichnisse einschließlich des angegebenen Verzeichnisses zu löschen) :

  1. Wenn File , löschen
  2. Wenn Empty Directory , löschen
  3. Wenn Not Empty Directory, löschen Sie erneut Löschen mit Unterverzeichnis, wiederholen Sie 1 bis 3

Beispiel:

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

Um Zugriff auf das externe Speicherverzeichnis zu erhalten, benötigen Sie die folgenden Berechtigungen:

(Verwenden Sie ContextCompat.checkSelfPermissionund ActivityCompat.requestPermissions)

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

Rekursive Methode:

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
quelle
0

Ich habe dieses hier platziert, obwohl es einen Ordner mit einer beliebigen Verzeichnisstruktur löscht.

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;

}

Hoffe das hilft.

user2288580
quelle
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) {
    }
}

Hier ist Ihre Lösung, die auch die Galerie aktualisiert.

Bilal Mustafa
quelle
0

Noch ein (moderner) Weg, um es zu lösen.

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

Auf Android seit 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
quelle