Как удалить всю папку и контент?

187

Я хочу, чтобы пользователи моего приложения могли удалять папку DCIM (которая находится на SD-карте и содержит подпапки).

Возможно ли это, если да, то как?

начинающий
источник
1
кроме рекурсивного подхода удаления снизу вверх?
Сарвар Эрфан
Если у вас очень большой или сложный каталог, вы должны использовать rm -rf directoryвместо FileUtils.deleteDirectory. После тестирования мы обнаружили, что это было в несколько раз быстрее. Посмотрите пример реализации здесь: stackoverflow.com/a/58421350/293280
Джошуа Пинтер

Ответы:

301

Позвольте мне сначала сказать вам, что вы не можете удалить папку DCIM, потому что это системная папка. Если вы удалите его вручную на телефоне, он удалит содержимое этой папки, но не папку DCIM. Вы можете удалить его содержимое, используя метод ниже:

Обновлено согласно комментариям

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
источник
3
эм как мне объявить что такое dir?
Новичок
Я в основном пытаюсь удалить все фотографии, поэтому не имеет значения, что DCIM не удаляется, пока фотографии ... так что даже удаление 100MEDIA папки внутри этого сделает свою работу
новичка
1
Вы должны объявить каталог, используя путь к папке dicm: use file r = file (path);
chikka.anddev
3
used File dir = new File (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Новичок
1
@chiragshah После удаления папки и воссоздания папки, в результате чего создается неизвестный файл с тем же именем, что и упомянутая папка. И если я пытаюсь получить доступ к этому файлу, он выдает исключение, например Ресурс или устройство занято. Я также проверил Свойства файл, где я нашел подпись MD5: сбой операции
ша
529

Вы можете рекурсивно удалять файлы и папки следующим образом:

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

    fileOrDirectory.delete();
}
teedyay
источник
21
Я не делал тестов на эффективность, но я считаю, что мой более надежный. chirag будет работать для конкретного случая папки DCIM, где папки в DCIM должны содержать только файлы (т.е. папки в DCIM обычно не содержат никаких подпапок). Моя версия удалит папки, вложенные на любую глубину. Существует вероятность того, что пользователь изменил содержимое своей SD-карты, чтобы DCIM содержал папки, вложенные более глубоко (например DCIM\foo\bar\pic.jpg), и в этом случае код chirag потерпит неудачу.
teedyay
2
Вопрос, который задал мне коллега: что произойдет, если на папке есть символическая ссылка, и вы выполняете этот кусок кода?
p4u144 18.12.12
1
@ p4u144 Дай своему коллеге высокую оценку за то, что он гений! Хорошо подмечено! Честно говоря, я не знаю, будет ли этот код уважать и следовать символическим ссылкам, но если это произойдет, у вас будет бесконечный цикл. Вы хотите это проверить?
teedyay
8
@ p4u144 Не беспокойтесь о символических ссылках. «С символическими ссылками ссылка удаляется, а не цель ссылки». от docs.oracle.com/javase/tutorial/essential/io/delete.html
Корбин
3
Здесь возможный NPE: fileOrDirectory.listFiles()может вернуться, nullесли при чтении файлов произошла ошибка ввода-вывода. Об этом ясно говорится в документации: developer.android.com/reference/java/io/File.html#listFiles ()
Брайан Йенчо,
67

Мы можем использовать аргументы командной строки, чтобы удалить всю папку и ее содержимое.

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

Пример использования приведенного выше кода:

deleteFiles("/sdcard/uploads/");
xinaxino
источник
2
кажется хорошим, вы знаете, если это синхронно или асинхронно? В документации не написано: developer.android.com/reference/java/lang/…
Кто-то где-то
2
Плохая идея. Почему это на оболочке?
Noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
sudocoder
34

В Kotlin вы можете использовать deleteRecursively()расширение из kotlin.ioпакета

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Дима Ростопира
источник
2
В Java вы можете использовать, FilesKt.deleteRecursively(new File("/path/to/dir"));если вы используете kotlin-stdlib
Joonsoo
Эта команда удалит каталог "/ dir" с содержимым внутри или только с содержимым внутри каталога "/ dir", и каталог останется там?
Бхимбим
1
@Bhimbim lemme google docs for you «Удалите этот файл со всеми его дочерними элементами». Итак, каталог будет удален так же, как и содержимое
Дима Ростопира
Спасибо @DimaRostopira!
Бхимбим
Котлин на помощь!
Тоби Ойелекан
15

Используйте метод ниже, чтобы удалить весь основной каталог, который содержит файлы и его подкаталог. После вызова этого метода еще раз вызовите каталог delete () вашего основного каталога.

// 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
источник
Из всех ответов это ЕДИНСТВЕННЫЙ реальный ответ, который также удаляет каталог после удаления файлов в нем.
Зеешан
Файл file = новый файл (Environment.getExternalStorageDirectory () + разделитель + «имя_папки» + разделитель); deleteDir (файл); да, это работает. Спасибо :)
ashishdhiman2007
14

Ваш подход подходит для папки, которая содержит только файлы, но если вы ищете сценарий, который также содержит подпапки, тогда необходима рекурсия

Также вы должны зафиксировать возвращаемое значение возврата, чтобы убедиться, что вы можете удалить файл

и включать

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

в вашем манифесте

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
источник
5
Это может быть проще, если вы используете для (File currentFile: file.listFiles ()) {
Thorben
8

Ответов много, но я решил добавить свой, потому что он немного другой. Он основан на ООП;)

Я создал класс DirectoryCleaner , который помогает мне каждый раз, когда мне нужно почистить какой-то каталог.

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

    }
}

Это может быть использовано для решения этой проблемы следующим образом:

File dir = new File(Environment.getExternalStorageDirectory(), "your_directory_name");
new DirectoryCleaner(dir).clean();
dir.delete();
Gio
источник
7

Если вам не нужно удалять вещи рекурсивно, вы можете попробовать что-то вроде этого:

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
источник
6

Вы не можете удалить каталог, если у него есть подкаталоги или файлы в Java. Попробуйте это простое решение из двух строк. Это позволит удалить каталог и конкурсы внутри каталога.

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

Добавьте эту строку в файл Gradle и синхронизируйте проект

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A
источник
Как 2 лайнера, это просто. Но установка всей библиотеки для использования только одного из ее методов кажется неэффективной. Используйте это вместо этого
Kathir
вставка наконечника gradle спасла мне жизнь.
Дракарис
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();
    }
}
Глубокая Верма
источник
5

увидеть android.os.FileUtils, это скрыть на API 21

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

Источник: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/FileUtils.java#414

edwardaa
источник
4

Согласно документации :

Если это абстрактное имя пути не обозначает каталог, тогда этот метод возвращает ноль.

Так что вы должны проверить, если listFilesесть, nullи продолжить, только если это не так

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.
источник
1
Это должен быть принятый ответ. Работает как шарм!
MSeiz5
3

Это то, что я делаю ... (кратко и проверено)

    ...
    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
источник
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
источник
2

Простой способ удалить все файлы из каталога:

Это общая функция для удаления всех изображений из каталога путем вызова только

deleteAllImageFile (контекст);

public static void deleteAllFile(Context context) {
File directory = context.getExternalFilesDir(null);
        if (directory.isDirectory()) {
            for (String fileName: file.list()) {
                new File(file,fileName).delete();
            }
        }    
    } 
Сагар Хорадж
источник
2

Самый безопасный код, который я знаю:

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

Проверяет, существует ли файл, обрабатывает ли нули, проверяет, был ли каталог фактически удален

Гари Дэвис
источник
2

Короткая колтинская версия

fun File.deleteDirectory(): Boolean {
    return if (exists()) {
        listFiles()?.forEach {
            if (it.isDirectory) {
                it.deleteDirectory()
            } else {
                it.delete()
            }
        }
        delete()
    } else false
}
Влад
источник
1

Вот нерекурсивная реализация, просто для удовольствия:

/**
 * 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
источник
1

Это (Пытается удалить все вложенные файлы и подкаталоги, включая предоставленный каталог) :

  1. Если Fileудалить
  2. Если Empty Directoryудалить
  3. если Not Empty Directory, вызовите удалить снова с подкаталогом, повторите с 1 по 3

пример:

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

Чтобы получить доступ к каталогу внешнего хранилища, вам необходимы следующие разрешения:

(Используйте ContextCompat.checkSelfPermissionи ActivityCompat.requestPermissions)

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

Рекурсивный метод:

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;
}
пьер
источник
0

Я поставил этот, хотя его темпами он удаляет папку с любой структурой каталогов.

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;

}

Надеюсь это поможет.

user2288580
источник
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) {
    }
}

Вот ваше решение, оно также обновит галерею.

Билал Мустафа
источник
0

Еще один (современный) способ ее решения.

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

На Android начиная с 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
источник
0

Я использую эту рекурсивную функцию, чтобы сделать работу:

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

Функция проверяет, является ли это каталогом или файлом.

Если это каталог, он проверяет, есть ли у него дочерние файлы, если у него есть дочерние файлы, он снова позвонит, передав дочерние файлы и повторив.

Если это файл, то удалите его.

(Не используйте эту функцию для очистки кеша приложения, передавая каталог кеша, потому что он также удалит каталог кеша, так что приложение будет аварийно завершать работу ... Если вы хотите очистить кеш, используйте эту функцию, которая не удалит Дир, вы переходите к нему:

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

или вы можете проверить, является ли это каталогом кеша, используя:

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

Пример кода для очистки кэша приложения:

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

До свидания, хорошего дня и кодирования: D

Z3R0
источник