Як видалити цілу папку та вміст?


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

3
Ем, як я можу оголосити, що таке реж?
Початківця

я в основному намагаюся видалити всі фотографії, тому не важливо, що DCIM не видаляється до тих пір, як фотографії ... так що навіть видалення 100MEDIA папки в цьому зробить роботу
Початок

1
Ви повинні оголосити каталог, використовуючи шлях до папки dicm: використовуйте файл r = файл (шлях);
chikka.anddev

3
використаний File dir = новий файл (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Початок

1
@chiragshah Після видалення папки та відтворення папки, в результаті чого створюється невідомий файл із таким самим ім'ям згаданої папки. І якщо я намагаюся отримати доступ до цього файлу, він викидає виключення, наприклад, " Ресурс" або "Пристрій зайнято". Я також перевірив "Властивості" файл, де я знайшов підпис MD5: Збій операції
sha

529

Ви можете видаляти файли та папки рекурсивно так:

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

    fileOrDirectory.delete();
}

21
Я не робив жодних тестів на ефективність, але я вважаю, що моя більш міцна. chirag's працюватиме в конкретному випадку папки DCIM, де папки в DCIM повинні містити лише файли (тобто папки в DCIM зазвичай не містять папок). Моя версія видалить папки, які вкладені на будь-яку глибину. Є ймовірність, що користувач змінив вміст своєї SD-карти, щоб DCIM містив папки, які вкладені більш глибоко (наприклад DCIM\foo\bar\pic.jpg), і в такому випадку код чірагу не вийде.
teedyay

2
Питання, яке колега запитав мене: Що станеться, якщо папка має символічне посилання на себе, і ви виконаєте цю частину коду?
p4u144

1
@ p4u144 Дайте своєму колезі високу п'ятірку за те, що він геній! Добре помічений! Якщо чесно, то я не знаю, чи буде цей код поважати чи слідувати символічним посиланням, але якщо він є, у вас буде нескінченний цикл. Ви любите тестувати це?
teedyay

8
@ p4u144 Не хвилюйтесь щодо символічних посилань. "З символічними посиланнями посилання видаляється, а не є ціллю посилання." від docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin

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

2
здається гарним, чи знаєте ви, чи це синхронно чи асинхронно? У документації не сказано: developer.android.com/reference/java/lang/…
хтось десь

2
Погана ідея. Навіщо це робити на оболонці?
noamtm


34

У Котліні ви можете використовувати 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 для вас "Видаліть цей файл із усіма його дітьми." Отже, каталог буде видалено, а також вміст
Діма Ростопіра,

Дякую @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();
}

З усіх відповідей, це ТІЛЬКА реальна відповідь, яка також видаляє каталог після видалення файлів у ньому.
zeeshan

Файл файлу = новий файл (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();
}

5
Це може бути простіше, якщо ви використовуєте для (Файл currentFile: file.listFiles ()) {
Thorben

8

Відповідей дуже багато, але я вирішив додати свою, бо це мало інакше. Він заснований на OOP;)

Я створив клас 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();

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

6

Ви не можете видалити каталог, якщо в ньому є підкаталоги або файли на Java. Спробуйте це дворядкове просте рішення. Це видалить каталог та конкурси всередині каталогу.

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

Додайте цей рядок у файл gradle та синхронізуйте проект

compile 'org.apache.commons:commons-io:1.3.2'  

Як 2 лайнера, це просто. Але встановлення цілої бібліотеки для використання лише одного з її методів видається неефективним. Використовуйте це замість
Катір

наконечник 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


4

Відповідно до документації :

Якщо це абстрактне ім'я шляху не позначає каталог, то цей метод повертає null.

Тож слід перевірити, чи 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());
}

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
    }

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

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

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;

}

Сподіваюся, це допомагає.


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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.