Jak usunąć cały folder i zawartość?

187

Chcę, aby użytkownicy mojej aplikacji mogli usunąć folder DCIM (który znajduje się na karcie SD i zawiera podfoldery).

Czy to możliwe, jeśli tak, to w jaki sposób?

Początkujący
źródło
1
inne niż rekurencyjne podejście oddolnego usuwania?
Sarwar Erfan
Jeśli masz bardzo duży lub złożony katalog, którego powinieneś użyć rm -rf directoryzamiast FileUtils.deleteDirectory. Po przeprowadzeniu testów porównawczych okazało się, że było wielokrotnie szybsze. Sprawdź przykładową implementację tutaj: stackoverflow.com/a/58421350/293280
Joshua Pinter

Odpowiedzi:

300

Pozwól, że powiem ci, że nie możesz usunąć folderu DCIM, ponieważ jest to folder systemowy. Usunięcie go ręcznie na telefonie spowoduje usunięcie zawartości tego folderu, ale nie folderu DCIM. Możesz usunąć jego zawartość za pomocą poniższej metody:

Zaktualizowano zgodnie z komentarzami

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
źródło
3
eerm, jak mam zadeklarować, co to jest reż?
Początkujący
w zasadzie próbuję usunąć wszystkie zdjęcia, więc nie ma znaczenia, że ​​DCIM nie jest usuwany, dopóki zdjęcia są ... więc nawet usunięcie 100MEDIA folder w tym miejscu wystarczy
Początkujący
1
musisz zadeklarować katalog, używając ścieżki do folderu dicm: użyj pliku r = plik (ścieżka);
chikka.anddev
3
używany Plik dir = nowy plik (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Początkujący
1
@chiragshah Po usunięciu folderu i ponownym utworzeniu folderu, co skutkuje utworzeniem nieznanego pliku o tej samej nazwie wspomnianego folderu. A jeśli próbuję uzyskać dostęp do tego pliku, zgłasza wyjątek, taki jak Zasób lub urządzenie zajęte. Sprawdziłem również Właściwości plik, w którym znalazłem podpis MD5: Niepowodzenie operacji
sha
529

Możesz usuwać pliki i foldery rekurencyjnie w następujący sposób:

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

    fileOrDirectory.delete();
}
teedyay
źródło
21
Nie wykonałem żadnych testów wydajności, ale uważam, że mój jest bardziej solidny. chirag będzie działał w konkretnym przypadku folderu DCIM, w którym foldery w DCIM powinny zawierać tylko pliki (tzn. foldery w DCIM zwykle nie zawierają żadnych podfolderów). Moja wersja usunie foldery zagnieżdżone na dowolnej głębokości. Istnieje prawdopodobieństwo, że użytkownik zmodyfikował zawartość swojej karty SD, dzięki czemu DCIM zawiera foldery zagnieżdżone głębiej (np. DCIM\foo\bar\pic.jpg), W którym to przypadku kod chirag zawiedzie.
teedyay
2
Pytanie, które zadał mi kolega: Co się stanie, jeśli folder ma na sobie link symboliczny i wykonasz ten fragment kodu?
p4u144,
1
@ p4u144 Daj swojemu koledze piątkę za bycie geniuszem! Dobrze zauważony! Szczerze mówiąc, nie wiem, czy ten kod szanuje i podąża za dowiązaniami symbolicznymi, ale jeśli tak, będziesz mieć nieskończoną pętlę. Czy masz ochotę to przetestować?
teedyay 18.12.12
8
@ p4u144 Nie martw się o linki symboliczne. „W przypadku dowiązań symbolicznych łącze jest usuwane, a nie cel łącza”. od docs.oracle.com/javase/tutorial/essential/io/delete.html
Corbin
3
Możliwe jest tutaj NPE: fileOrDirectory.listFiles()może zwrócić, nulljeśli podczas odczytu plików wystąpi błąd we / wy. Jest to wyraźnie określone w dokumentacji: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho
67

Możemy użyć argumentów wiersza poleceń, aby usunąć cały folder i jego zawartość.

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

Przykładowe użycie powyższego kodu:

deleteFiles("/sdcard/uploads/");
Xinaxino
źródło
2
wydaje się dobre, czy wiesz, czy jest to synchroniczne czy asynchroniczne? Dokumentacja nie mówi: developer.android.com/reference/java/lang/…
Someone Somewhere
2
Kiepski pomysł. Dlaczego to robi na skorupce?
noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
sudocoder
34

W Kotlin możesz użyć deleteRecursively()rozszerzenia z kotlin.iopakietu

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Dima Rostopira
źródło
2
W Javie możesz używać, FilesKt.deleteRecursively(new File("/path/to/dir"));jeśli używasz kotlin-stdlib
Joonsoo
To polecenie usunie katalog „/ dir” z zawartością w nim lub tylko zawartością w katalogu „/ dir”, a katalog pozostanie tam?
Bhimbim
1
@Bhimbim lemme google docs for you „Usuń ten plik ze wszystkimi jego dziećmi”. Tak więc katalog zostanie usunięty, podobnie jak zawartość
Dima Rostopira
Dziękuję @DimaRostopira!.
Bhimbim
kotlin na ratunek!
Tobi Oyelekan
15

użyj poniższej metody, aby usunąć cały katalog główny zawierający pliki i jego podkatalog. Po wywołaniu tej metody jeszcze raz wywołaj katalog delete () z katalogu głównego.

// 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
źródło
Spośród wszystkich odpowiedzi jest to TYLKO prawdziwa odpowiedź, która usuwa katalog również po usunięciu zawartych w nim plików.
zeeshan
Plik plik = nowy plik (Environment.getExternalStorageDirectory () + separator + „nazwa folderu” + separator); deleteDir (plik); Tak, to działa. Dzięki :)
ashishdhiman2007
14

Twoje podejście jest przyzwoite w przypadku folderu zawierającego tylko pliki, ale jeśli szukasz scenariusza zawierającego również podfoldery, konieczna jest rekursja

Powinieneś również przechwycić wartość zwracanego zwrotu, aby upewnić się, że możesz usunąć plik

i obejmują

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

w twoim manifeście

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
źródło
5
Może to być łatwiejsze, jeśli używasz dla (File currentFile: file.listFiles ()) {
Thorben
8

Istnieje wiele odpowiedzi, ale zdecydowałem się dodać własną, ponieważ jest trochę inna. Opiera się na OOP;)

Stworzyłem klasę DirectoryCleaner , która pomaga mi za każdym razem, gdy muszę wyczyścić jakiś katalog.

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

    }
}

Można go użyć do rozwiązania tego problemu w następujący sposób:

File dir = new File(Environment.getExternalStorageDirectory(), "your_directory_name");
new DirectoryCleaner(dir).clean();
dir.delete();
Gio
źródło
7

Jeśli nie musisz usuwać rzeczy rekurencyjnie, możesz spróbować czegoś takiego:

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
źródło
6

Nie można usunąć katalogu, jeśli zawiera on podkatalogi lub pliki w Javie. Wypróbuj to dwuwierszowe proste rozwiązanie. Spowoduje to usunięcie katalogu i konkursów w katalogu.

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

Dodaj tę linię do pliku stopni i zsynchronizuj projekt

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A
źródło
Jako 2-liniowy jest prosty. Ale instalowanie całej biblioteki w celu wykorzystania tylko jednej z jej metod wydaje się nieefektywne. Użyj tego zamiast tego
Kathir
końcówka wkładki stopniowej uratowała mi życie.
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();
    }
}
Deep Verma
źródło
4

Zgodnie z dokumentacją :

Jeśli ta abstrakcyjna nazwa ścieżki nie oznacza katalogu, wówczas ta metoda zwraca null.

Więc powinieneś sprawdzić, czy listFilesjest nulli kontynuować tylko, jeśli nie jest

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.
źródło
1
To powinna być zaakceptowana odpowiedź. Działa jak marzenie!
MSeiz5
3

To właśnie robię ... (zwięzłe i przetestowane)

    ...
    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
źródło
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
źródło
2

Prosty sposób na usunięcie wszystkich plików z katalogu:

Jest to ogólna funkcja usuwania wszystkich obrazów z katalogu tylko poprzez wywołanie

deleteAllImageFile (kontekst);

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
źródło
2

Najbezpieczniejszy kod, jaki znam:

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

Sprawdza, czy plik istnieje, obsługuje wartości null, sprawdza, czy katalog został faktycznie usunięty

Gary Davies
źródło
2

Krótka wersja koltin

fun File.deleteDirectory(): Boolean {
    return if (exists()) {
        listFiles()?.forEach {
            if (it.isDirectory) {
                it.deleteDirectory()
            } else {
                it.delete()
            }
        }
        delete()
    } else false
}
Vlad
źródło
1

Oto nierekurencyjna implementacja, dla zabawy:

/**
 * 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
źródło
1

To (próbuje usunąć wszystkie podkatalogi i podkatalogi, w tym dostarczony katalog) :

  1. Jeśli File , usuń
  2. Jeśli Empty Directory , usuń
  3. jeśli Not Empty Directory, wywołaj usuń ponownie z podkatalogiem, powtórz od 1 do 3

przykład:

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

Aby uzyskać dostęp do Zewnętrznego katalogu pamięci, potrzebujesz następujących uprawnień:

(Użyj ContextCompat.checkSelfPermissioni ActivityCompat.requestPermissions)

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

Metoda rekurencyjna:

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
źródło
0

Umieściłem ten choć jego tempo usuwa folder o dowolnej strukturze katalogów.

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;

}

Mam nadzieję że to pomoże.

użytkownik2288580
źródło
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) {
    }
}

oto twoje rozwiązanie, które odświeży również galerię.

Bilal Mustafa
źródło
0

Kolejny (nowoczesny) sposób na rozwiązanie tego problemu.

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

Na Androida od 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
źródło
0

Używam tej funkcji rekurencyjnej do wykonania zadania:

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

Funkcja sprawdza, czy jest to katalog, czy plik.

Jeśli jest to katalog, sprawdza, czy ma pliki potomne, czy ma pliki potomne, zadzwoni ponownie, przekazując dzieci i powtarzając.

Jeśli jest to plik, usuń go.

(Nie używaj tej funkcji, aby wyczyścić pamięć podręczną aplikacji, przekazując katalog pamięci podręcznej, ponieważ spowoduje to również usunięcie katalogu pamięci podręcznej, więc aplikacja się zawiesi ... Jeśli chcesz wyczyścić pamięć podręczną, użyj tej funkcji, która nie usunie zdajesz sobie z tego sprawę:

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

lub możesz sprawdzić, czy jest to katalog pamięci podręcznej, używając:

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

Przykładowy kod do wyczyszczenia pamięci podręcznej aplikacji:

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

Cześć, miłego dnia i kodowania: D

Z3R0
źródło