Как мне удалить / удалить папку, которая не пуста?

Я получаю сообщение об ошибке «Доступ запрещен» при попытке удалить непустую папку. В своей попытке я использовал следующую команду: os.remove("/folder_name").

Каков наиболее эффективный способ удаления / удаления папки / каталога, который не пуст?

Также обратите внимание, что даже если каталог был пуст, os.remove снова завершился бы ошибкой, потому что правильная функция - os.rmdir.

tzot 20.11.2008 01:56

И для конкретного поведения rm -rf см .: stackoverflow.com/questions/814167/…

Ciro Santilli新疆棉花TRUMP BAN BAD 19.12.2014 10:41
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
929
2
743 270
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

Ответ принят как подходящий
import shutil

shutil.rmtree('/folder_name')

Ссылка на стандартную библиотеку: shutil.rmtree.

По своей конструкции rmtree не работает в деревьях папок, содержащих файлы, доступные только для чтения. Если вы хотите, чтобы папка была удалена независимо от того, содержит ли она файлы только для чтения, используйте

shutil.rmtree('/folder_name', ignore_errors=True)

Обратите внимание, что rmtree выйдет из строя, если есть файлы только для чтения: stackoverflow.com/questions/2656322/…

Sridhar Ratnakumar 17.04.2010 02:02

У меня это не работает: Traceback (последний вызов последним): файл "foo.py", строка 31, в <module> shutil.rmtree (thistestdir) Файл "/usr/lib/python2.6/shutil.py ", строка 225, в rmtree onerror (os.rmdir, path, sys.exc_info ()) Файл" /usr/lib/python2.6/shutil.py ", строка 223, в rmtree os.rmdir (путь) OSError: [Errno 90] Каталог не пуст: '/ path / to / rmtree'

Clayton Hughes 14.09.2011 22:55

Клейтон: по всей вероятности, файл был добавлен одновременно, когда rmtree была занята удалением материала, "rm -rf" не удастся.

ddaa 15.09.2011 01:43

Кто-нибудь знает, почему этой функции нет в пакете os? Похоже, что os.rmdir совершенно бесполезен. Есть ли веские аргументы в пользу того, почему это реализовано таким образом?

Malcolm 24.09.2013 04:43

@Malcolm Пакет является оболочкой для функций ОС. В системах POSIXrmdir не работает, если каталог не пуст. Ubuntu и Окна являются популярными примерами соответствия POSIX в этом отношении.

Iain Samuel McLean Elder 04.10.2013 15:03

@Malcolm Это полезно только тогда, когда вы ожидаете, что каталог будет пустым в то время, когда вы его удаляете. Вы должны предшествовать вызову rmdir с явным списком файлов для удаления. например чтобы убедиться, что вы удаляете только файлы, созданные вашей программой. Я считаю, что это аналог O_EXCL, когда вы открываете файл, когда на затронутый файл ставится предварительное условие. Кроме того, как говорит Элдер, POSIX

init_js 12.04.2019 20:44

AttributeError: модуль shutil не имеет атрибута rmtrees

Leos313 21.02.2020 12:45

Обратите внимание, что ignore_errors=True не гарантирует, что файлы будут удалены. Может быть PermissionError или WinError, см. bugs.python.org/issue33240

Elliott B 03.09.2020 06:16

Из документы python на os.walk():

# Delete everything reachable from the directory named in 'top',
# assuming there are no symbolic links.
# CAUTION:  This is dangerous!  For example, if top == '/', it
# could delete all your disk files.
import os
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))

Что ж, может я ошибаюсь в даунмодинге. Но я могу, сейчас думаю, что это правильно.

ddaa 19.11.2008 23:39

@ddaa: Хотя использование shutil, безусловно, является самым простым способом, в этом решении, безусловно, нет ничего необычного. Я бы не проголосовал за этот ответ, но у меня есть время только отменить ваш голос против :)

Jeremy Cantrell 20.11.2008 00:18

Сам код питонический. Использование его вместо shutil.rmtree в реальной программе было бы непифоничным: это означало бы игнорирование «одного очевидного способа сделать это». Во всяком случае, это семантика, убирающая даунмод.

ddaa 20.11.2008 00:50

@ddaa Неужели нежелательно регистрировать каждый удаленный файл или каталог? Я не уверен, как это сделать с помощью shutil.rmtree?

Jonathan Komar 26.01.2017 11:17

@ macmadness86 Ваш комментарий должен быть отдельным вопросом. Короче говоря, shutil.rmtree этого не делает. Это не имеет ничего общего с питоническим или нет.

ddaa 26.01.2017 16:32

@ddaa Это была пища для размышлений, то есть риторика. Я знаю, что я делаю. Я просто подумал, что вы, возможно, захотите пересмотреть «очевидный способ сделать это», указав причину, по которой shutil.rmtree может не подходить для этого.

Jonathan Komar 26.01.2017 18:14

В комментариях в shutil указано, что вы можете копировать и изменять функции, чтобы адаптировать их к вашим потребностям. Например, в Windows shutil.rmtree работает не слишком хорошо, потому что os.chmod иногда нужно применять к файлам (иначе он не работает, в отличие от Un * x)

Jean-François Fabre 24.07.2017 11:39

В Windows мне не удалось заставить работать shutil.rmtree (попробовал ignore_errors = True и создал настраиваемую функцию onerror, чтобы сбросить бит только для чтения), но этот метод работал нормально.

csteel 02.12.2019 22:30

если вы уверены, что хотите удалить все дерево каталогов и больше не интересуетесь содержимым каталога, то сканирование всего дерева каталогов - глупость ... просто вызовите собственную команду ОС из python, чтобы сделать это. Это будет быстрее, эффективнее и потребляет меньше памяти.

RMDIR c:\blah /s /q 

или * nix

rm -rf /home/whatever 

В python код будет выглядеть так ..

import sys
import os

mswindows = (sys.platform == "win32")

def getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""
    if not mswindows:
        return commands.getstatusoutput(cmd)
    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text


def deleteDir(path):
    """deletes the path entirely"""
    if mswindows: 
        cmd = "RMDIR "+ path +" /s /q"
    else:
        cmd = "rm -rf "+path
    result = getstatusoutput(cmd)
    if (result[0]!=0):
        raise RuntimeError(result[1])

-1. Весь смысл использования shutil.rmdir состоит в том, чтобы изолировать вас от типа операционной системы.

mtrw 22.12.2010 11:32

Я понимаю концепцию, но когда кто-то хорошо осведомлен о том, что он хочет полностью удалить папку, тогда какой смысл сканировать все дерево файлов? shutil.rmdir специально вызывает os.listdir (), os.path.islink () и т. д. некоторые проверки, которые на самом деле не всегда нужны, поскольку все, что нужно, - это отсоединить узел файловой системы. Помимо некоторых систем сборки, таких как MSWindows для разработки MSAuto / WinCE, shtuil.rmdir почти всегда дает сбой, так как пакетная разработка MSAuto блокирует некоторые странные файлы сборки при неудачном выходе, и только rmdir / S / Q или перезагрузка полезны для очистки их.

P M 23.12.2010 11:10

@PM what's the point of crawling the entire file tree ? shutil.rmdir specifically call os.listdir(), os.path.islink() etc etc.. - Ну да. Другого пути нет. rm и RMDIR делают то же самое.

Izkata 11.02.2012 01:01

да, просто rm ближе к ядру, используя меньше времени, памяти и процессора ... и, как я уже сказал, причина, по которой я использовал этот метод, была из-за блокировок, оставленных сценариями пакетной сборки MSAuto ...

P M 11.02.2012 22:25

Да, но использование shutil делает код кроссплатформенным и абстрагирует детали платформы.

xshoppyx 03.08.2013 06:23

Я просто сталкиваюсь с проблемой, когда удаляемый каталог содержит подкаталог с 000 правами. shutil.rmdir здесь не удалось. rm -rf сработал. Очевидно, shutil.rmdir не транслируется в rm -rf в Linux.

user2389519 27.10.2013 00:18

Я не думаю, что за этот ответ следует проголосовать ниже 1, поскольку он предоставляет очень хорошую ссылку для работы в определенных ситуациях, в которых может быть заинтересован читатель. Мне нравится, когда несколько методов публикуются с ранжированием по порядку. Так что, хотя мне и не нужно это использовать, теперь я знаю, что это можно сделать и как это сделать.

kmcguire 06.06.2014 15:45

Я не уверен на 100%, но разве собственные команды ОС (например, rm -rf) не должны внутренне проходить по всему дереву каталогов? Если этого не сделать, все файлы не будут удалены.

kapad 14.10.2019 23:32
import shutil
shutil.rmtree(dest, ignore_errors=True)

Это правильный ответ. В моей системе, даже если я настроил все в конкретной папке на запись-чтение, я получаю сообщение об ошибке при попытке удалить. ignore_errors=True решает проблему.

Aventinus 07.10.2016 17:36

В моем ответе вместо onerror используется параметр ignore_errors. Таким образом файлы, доступные только для чтения, удаляются, а не игнорируются.

Dave Chandler 11.05.2017 14:47

Да, это не приведет к удалению файлов в случае ошибки. Таким образом, в основном игнорируется весь метод rmtree().

Juha Untinen 16.09.2017 04:43

Это должно было быть небольшим изменением ответа, принятого 6 годами ранее, а не новым ответом. Я сделаю это сейчас.

Jean-François Corbett 23.02.2018 15:01
import os
import stat
import shutil

def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        # raiseenter code here

shutil.rmtree(path, ignore_errors=False, onerror=errorRemoveReadonly) 

Если установлено ignore_errors, ошибки игнорируются; в противном случае, если установлена ​​ошибка onerror, она вызывается для обработки ошибки с аргументами (func, path, exc_info), где func - это os.listdir, os.remove или os.rmdir; path - это аргумент той функции, которая вызвала сбой; а exc_info - это кортеж, возвращаемый sys.exc_info (). Если ignore_errors имеет значение false, а onerror равно None, возникает исключение. Введите здесь код.

Согласно документы, Исключения, вызванные onerror, не будут обнаружены, поэтому я не уверен, что ваш поднять введите код здесь что-то значит.

kmarsh 03.11.2015 19:30

-1. Это кажется слишком сложным по сравнению с ответом Дэйва Чендлера. Кроме того, если мы хотим удалить только чтение, нам не нужно делать файлы исполняемыми.

idbrii 01.03.2019 20:47

из python 3.4 вы можете использовать:

import pathlib

def delete_folder(pth) :
    for sub in pth.iterdir() :
        if sub.is_dir() :
            delete_folder(sub)
        else :
            sub.unlink()
    pth.rmdir() # if you just want to delete the dir content but not the dir itself, remove this line

где pth - это экземпляр pathlib.Path. Красиво, но может быть не самым быстрым.

Основываясь на ответе kkubasik, проверьте, существует ли папка перед удалением, более надежный

import shutil
def remove_folder(path):
    # check if folder exists
    if os.path.exists(path):
         # remove if exists
         shutil.rmtree(path)
    else:
         # throw your exception to handle this special scenario
         raise XXError("your exception") 
remove_folder("/folder_name")

это вводит возможное состояние гонки

Corey Goldberg 30.04.2017 04:31

согласно самый-питонический-способ-удалить-файл-который-может-не-существовать, предпочтительнее удалить try и обработать except, чем сначала вызвать exists()

TT-- 02.02.2018 04:45

Вы можете использовать команду os.system для простоты:

import os
os.system("rm -rf dirname")

Очевидно, что он фактически вызывает системный терминал для выполнения этой задачи.

Извините, это Unpythonic и зависит от платформы.

Ami Tavory 24.01.2016 15:20

Если вы не хотите использовать модуль shutil, вы можете просто использовать модуль os.

from os import listdir, rmdir, remove
for i in listdir(directoryToRemove):
    os.remove(os.path.join(directoryToRemove, i))
rmdir(directoryToRemove) # Now the directory is empty of files
os.remove не может удалить каталоги, поэтому это вызовет OsError, если directoryToRemove содержит подкаталоги.
Eponymous 28.05.2017 20:18

#pronetoraceconditions

kapad 14.10.2019 23:35

Просто несколько вариантов Python 3.5, чтобы завершить ответы выше. (Мне бы очень хотелось найти их здесь).

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

Удалить папку, если пуста

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

Удалите также папку, если она содержит этот файл

    elif subdirs == [] and len(files) == 1: # if contains no sub folder and only 1 file 
        if files[0]== "desktop.ini" or:  
            send2trash(dir)
            print(dir, ": folder removed")
        else:
            print(dir)

удалить папку, если она содержит только файлы .srt или .txt

    elif subdirs == []: #if dir doesn’t contains subdirectory
        ext = (".srt", ".txt")
        contains_other_ext=0
        for file in files:
            if not file.endswith(ext):  
                contains_other_ext=True
        if contains_other_ext== 0:
                send2trash(dir)
                print(dir, ": dir deleted")

Удалите папку, если ее размер меньше 400 Кб:

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total


for dir, subdirs, files in os.walk(root):   
    If get_tree_size(dir) < 400000:  # ≈ 400kb
        send2trash(dir)
    print(dir, "dir deleted")

Исправьте отступ и код if files[0]== "desktop.ini" or:

Mr_and_Mrs_D 26.06.2017 17:08

От docs.python.org:

This example shows how to remove a directory tree on Windows where some of the files have their read-only bit set. It uses the onerror callback to clear the readonly bit and reattempt the remove. Any subsequent failure will propagate.

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

Чтобы удалить папку, даже если она может не существовать (избегая состояния гонки в Ответ Чарльза Чоу), но все еще иметь ошибки, когда другие вещи идут не так (например, проблемы с разрешениями, ошибка чтения с диска, файл не является каталогом)

Для Python 3.x:

import shutil

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, FileNotFoundError):
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

Код Python 2.7 почти такой же:

import shutil
import errno

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, OSError) and \
        except_instance.errno == errno.ENOENT:
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)
def deleteDir(dirPath):
    deleteFiles = []
    deleteDirs = []
    for root, dirs, files in os.walk(dirPath):
        for f in files:
            deleteFiles.append(os.path.join(root, f))
        for d in dirs:
            deleteDirs.append(os.path.join(root, d))
    for f in deleteFiles:
        os.remove(f)
    for d in deleteDirs:
        os.rmdir(d)
    os.rmdir(dirPath)

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

racribeiro 04.11.2018 16:42

Я нашел очень простой способ удалить любой папка (даже НЕ пустая) или файл на ОС Windows.

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)

С os.walk я бы предложил решение, которое состоит из трех однострочных вызовов Python:

python -c "import sys; import os; [os.chmod(os.path.join(rs,d), 0o777) for rs,ds,fs in os.walk(_path_) for d in ds]"
python -c "import sys; import os; [os.chmod(os.path.join(rs,f), 0o777) for rs,ds,fs in os.walk(_path_) for f in fs]"
python -c "import os; import shutil; shutil.rmtree(_path_, ignore_errors=False)"

Первый сценарий chmod - все подкаталоги, второй сценарий - все файлы chmod. Затем третий скрипт удаляет все без препятствий.

Я тестировал это из «Shell Script» в задании Jenkins (я не хотел хранить новый скрипт Python в SCM, поэтому искал однострочное решение), и это сработало для Linux и Windows.

С pathlib вы можете объединить первые два шага в один: [p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]

pepoluan 17.06.2019 02:25

Десять лет спустя, используя Python 3.7 и Linux, все еще есть разные способы сделать это:

import subprocess
from pathlib import Path

#using pathlib.Path
path = Path('/path/to/your/dir')
subprocess.run(["rm", "-rf", str(path)])

#using strings
path = "/path/to/your/dir"
subprocess.run(["rm", "-rf", path])

По сути, он использует модуль подпроцесса Python для запуска сценария bash $ rm -rf '/path/to/your/dir, как если бы вы использовали терминал для выполнения той же задачи. Это не полностью Python, но он справляется.

Я включил пример pathlib.Path потому, что, по моему опыту, он очень полезен при работе со многими изменяющимися путями. Дополнительные шаги по импорту модуля pathlib.Path и преобразованию конечных результатов в строки часто обходятся мне дешевле времени разработки. Было бы удобно, если бы Path.rmdir() поставлялся с опцией arg для явной обработки непустых каталогов.

Я также перешел на этот подход, потому что у меня возникли проблемы с rmtree и скрытыми папками, такими как .vscode. Эта папка была обнаружена как текстовый файл, и ошибка сообщила мне, что этот файл был busy и не может быть удален.

Daniel Eisenreich 03.04.2020 11:54

Для Windows, если каталог не пуст, и у вас есть файлы, доступные только для чтения, или вы получаете такие ошибки, как

  • Access is denied
  • The process cannot access the file because it is being used by another process

Попробуй, os.system('rmdir /S /Q "{}"'.format(directory))

Это эквивалент rm -rf в Linux / Mac.

Я хотел бы добавить подход "чистого pathlib":

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    """
    Delete a given directory and its subdirectories.

    :param target: The directory to delete
    :param only_if_empty: Raise RuntimeError if any file is found in the tree
    """
    target = Path(target).expanduser()
    assert target.is_dir()
    for p in sorted(target.glob('**/*'), reverse=True):
        if not p.exists():
            continue
        p.chmod(0o666)
        if p.is_dir():
            p.rmdir()
        else:
            if only_if_empty:
                raise RuntimeError(f'{p.parent} is not empty!')
            p.unlink()
    target.rmdir()

Это основано на том факте, что Path можно заказать, и более длинные пути всегда будут отсортированы после более коротких, как и str. Следовательно, каталоги будут предшествовать файлам. Если мы обратный сортировки, файлы будут располагаться перед соответствующими контейнерами, поэтому мы можем просто отсоединить / rmdir их один за другим за один проход.

Выгоды:

  • Он НЕ полагается на внешние двоичные файлы: все использует модули Python с батарейками (Python> = 3.6)
    • Это означает, что не нужно повторно запускать новый подпроцесс для отключения.
  • Это довольно быстро и просто; вам не нужно реализовывать свою собственную рекурсию
  • Это кроссплатформенный (по крайней мере, это то, что pathlib обещает в Python 3.6; ни одна из указанных выше операций не работает в Windows)
  • При необходимости можно вести подробный журнал, например, записывать каждое удаление по мере его возникновения.

Можете ли вы также предоставить пример использования, например. del_dir (Путь ())? Спасибо

lcapra 28.08.2019 11:18

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

pepoluan 30.08.2019 10:11

«Это быстро и эффективно с точки зрения памяти: нет стека рекурсии, нет необходимости запускать подпроцесс» - на самом деле это не так. В рекурсивной подстановке все еще продолжается рекурсия. Это также неэффективно с точки зрения памяти, потому что вы создаете два списка, содержащих пути ко всем файлам и папкам: встроенная функция sorted сначала создает список элементов, возвращаемых генератором glob, а затем создает новый список с отсортированными элементами. В зависимости от количества файлов это может привести к значительному потреблению памяти. О, и вы вводите сортировку с временной сложностью n log n.

danzel 28.10.2020 13:23

@danzel, ты технически прав. Отредактирую свой ответ, чтобы не вводить в заблуждение.

pepoluan 31.10.2020 11:37

@danzel сказал: я не думаю, что сортировка будет медленнее, чем многократный запуск подпроцесса для выполнения команд оболочки с использованием os.system или subprocess.run. Также память, необходимая для поддержки списка + отсортированный список, вероятно, меньше, чем память, необходимая для запуска подпроцесса и его запуска. YMMV

pepoluan 31.10.2020 11:44

В моем случае единственным способом удаления было использование всех возможностей, потому что мой код должен был запускаться либо с помощью cmd.exe, либо с помощью powershell.exe. Если это ваш случай, просто создайте функцию с этим кодом, и все будет в порядке:

        #!/usr/bin/env python3

        import shutil
        from os import path, system
        import sys

        # Try to delete the folder ---------------------------------------------
        if (path.isdir(folder)):
            shutil.rmtree(folder, ignore_errors=True)

        if (path.isdir(folder)):
            try:
                system("rd -r {0}".format(folder))
            except Exception as e:
                print("WARN: Failed to delete => {0}".format(e),file=sys.stderr)

        if (path.isdir(self.backup_folder_wrk)):
            try:
                system("rd /s /q {0}".format(folder))
            except Exception as e:
                print("WARN: Failed to delete => {0}".format(e),file=sys.stderr)

        if (path.isdir(folder)):
            print("WARN: Failed to delete {0}".format(folder),file=sys.stderr)
        # -------------------------------------------------------------------------------------

Основанное на рекурсии, чистое решение pathlib:

from pathlib import Path

def remove_path(path: Path):
    if path.is_file() or path.is_symlink():
        path.unlink()
        return
    for p in path.iterdir():
        remove_path(p)
    path.rmdir()

Поддерживает Windows и символические ссылки

Другие вопросы по теме