Я получаю сообщение об ошибке «Доступ запрещен» при попытке удалить непустую папку. В своей попытке я использовал следующую команду: os.remove("/folder_name").
Каков наиболее эффективный способ удаления / удаления папки / каталога, который не пуст?
И для конкретного поведения rm -rf см .: stackoverflow.com/questions/814167/…






import shutil
shutil.rmtree('/folder_name')
Ссылка на стандартную библиотеку: shutil.rmtree.
По своей конструкции rmtree не работает в деревьях папок, содержащих файлы, доступные только для чтения. Если вы хотите, чтобы папка была удалена независимо от того, содержит ли она файлы только для чтения, используйте
shutil.rmtree('/folder_name', ignore_errors=True)
Обратите внимание, что rmtree выйдет из строя, если есть файлы только для чтения: stackoverflow.com/questions/2656322/…
У меня это не работает: 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'
Клейтон: по всей вероятности, файл был добавлен одновременно, когда rmtree была занята удалением материала, "rm -rf" не удастся.
Кто-нибудь знает, почему этой функции нет в пакете os? Похоже, что os.rmdir совершенно бесполезен. Есть ли веские аргументы в пользу того, почему это реализовано таким образом?
@Malcolm Пакет является оболочкой для функций ОС. В системах POSIXrmdir не работает, если каталог не пуст. Ubuntu и Окна являются популярными примерами соответствия POSIX в этом отношении.
@Malcolm Это полезно только тогда, когда вы ожидаете, что каталог будет пустым в то время, когда вы его удаляете. Вы должны предшествовать вызову rmdir с явным списком файлов для удаления. например чтобы убедиться, что вы удаляете только файлы, созданные вашей программой. Я считаю, что это аналог O_EXCL, когда вы открываете файл, когда на затронутый файл ставится предварительное условие. Кроме того, как говорит Элдер, POSIX
AttributeError: модуль shutil не имеет атрибута rmtrees
Обратите внимание, что ignore_errors=True не гарантирует, что файлы будут удалены. Может быть PermissionError или WinError, см. bugs.python.org/issue33240
Из документы 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: Хотя использование shutil, безусловно, является самым простым способом, в этом решении, безусловно, нет ничего необычного. Я бы не проголосовал за этот ответ, но у меня есть время только отменить ваш голос против :)
Сам код питонический. Использование его вместо shutil.rmtree в реальной программе было бы непифоничным: это означало бы игнорирование «одного очевидного способа сделать это». Во всяком случае, это семантика, убирающая даунмод.
@ddaa Неужели нежелательно регистрировать каждый удаленный файл или каталог? Я не уверен, как это сделать с помощью shutil.rmtree?
@ macmadness86 Ваш комментарий должен быть отдельным вопросом. Короче говоря, shutil.rmtree этого не делает. Это не имеет ничего общего с питоническим или нет.
@ddaa Это была пища для размышлений, то есть риторика. Я знаю, что я делаю. Я просто подумал, что вы, возможно, захотите пересмотреть «очевидный способ сделать это», указав причину, по которой shutil.rmtree может не подходить для этого.
В комментариях в shutil указано, что вы можете копировать и изменять функции, чтобы адаптировать их к вашим потребностям. Например, в Windows shutil.rmtree работает не слишком хорошо, потому что os.chmod иногда нужно применять к файлам (иначе он не работает, в отличие от Un * x)
В Windows мне не удалось заставить работать shutil.rmtree (попробовал ignore_errors = True и создал настраиваемую функцию onerror, чтобы сбросить бит только для чтения), но этот метод работал нормально.
если вы уверены, что хотите удалить все дерево каталогов и больше не интересуетесь содержимым каталога, то сканирование всего дерева каталогов - глупость ... просто вызовите собственную команду ОС из 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 состоит в том, чтобы изолировать вас от типа операционной системы.
Я понимаю концепцию, но когда кто-то хорошо осведомлен о том, что он хочет полностью удалить папку, тогда какой смысл сканировать все дерево файлов? shutil.rmdir специально вызывает os.listdir (), os.path.islink () и т. д. некоторые проверки, которые на самом деле не всегда нужны, поскольку все, что нужно, - это отсоединить узел файловой системы. Помимо некоторых систем сборки, таких как MSWindows для разработки MSAuto / WinCE, shtuil.rmdir почти всегда дает сбой, так как пакетная разработка MSAuto блокирует некоторые странные файлы сборки при неудачном выходе, и только rmdir / S / Q или перезагрузка полезны для очистки их.
@PM what's the point of crawling the entire file tree ? shutil.rmdir specifically call os.listdir(), os.path.islink() etc etc.. - Ну да. Другого пути нет. rm и RMDIR делают то же самое.
да, просто rm ближе к ядру, используя меньше времени, памяти и процессора ... и, как я уже сказал, причина, по которой я использовал этот метод, была из-за блокировок, оставленных сценариями пакетной сборки MSAuto ...
Да, но использование shutil делает код кроссплатформенным и абстрагирует детали платформы.
Я просто сталкиваюсь с проблемой, когда удаляемый каталог содержит подкаталог с 000 правами. shutil.rmdir здесь не удалось. rm -rf сработал. Очевидно, shutil.rmdir не транслируется в rm -rf в Linux.
Я не думаю, что за этот ответ следует проголосовать ниже 1, поскольку он предоставляет очень хорошую ссылку для работы в определенных ситуациях, в которых может быть заинтересован читатель. Мне нравится, когда несколько методов публикуются с ранжированием по порядку. Так что, хотя мне и не нужно это использовать, теперь я знаю, что это можно сделать и как это сделать.
Я не уверен на 100%, но разве собственные команды ОС (например, rm -rf) не должны внутренне проходить по всему дереву каталогов? Если этого не сделать, все файлы не будут удалены.
import shutil
shutil.rmtree(dest, ignore_errors=True)
Это правильный ответ. В моей системе, даже если я настроил все в конкретной папке на запись-чтение, я получаю сообщение об ошибке при попытке удалить. ignore_errors=True решает проблему.
В моем ответе вместо onerror используется параметр ignore_errors. Таким образом файлы, доступные только для чтения, удаляются, а не игнорируются.
Да, это не приведет к удалению файлов в случае ошибки. Таким образом, в основном игнорируется весь метод rmtree().
Это должно было быть небольшим изменением ответа, принятого 6 годами ранее, а не новым ответом. Я сделаю это сейчас.
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, не будут обнаружены, поэтому я не уверен, что ваш поднять введите код здесь что-то значит.
-1. Это кажется слишком сложным по сравнению с ответом Дэйва Чендлера. Кроме того, если мы хотим удалить только чтение, нам не нужно делать файлы исполняемыми.
из 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")
это вводит возможное состояние гонки
согласно самый-питонический-способ-удалить-файл-который-может-не-существовать, предпочтительнее удалить try и обработать except, чем сначала вызвать exists()
Вы можете использовать команду os.system для простоты:
import os
os.system("rm -rf dirname")
Очевидно, что он фактически вызывает системный терминал для выполнения этой задачи.
Извините, это Unpythonic и зависит от платформы.
Если вы не хотите использовать модуль 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 содержит подкаталоги.
#pronetoraceconditions
Просто несколько вариантов 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:
От 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)
Замечательно создать скрипт, который помещает файл в карантин перед тем, как удалить его вслепую.
Я нашел очень простой способ удалить любой папка (даже НЕ пустая) или файл на ОС 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("**/*")]
Десять лет спустя, используя 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 и не может быть удален.
Для Windows, если каталог не пуст, и у вас есть файлы, доступные только для чтения, или вы получаете такие ошибки, как
Access is deniedThe 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 их один за другим за один проход.
Выгоды:
pathlib обещает в Python 3.6; ни одна из указанных выше операций не работает в Windows)Можете ли вы также предоставить пример использования, например. del_dir (Путь ())? Спасибо
@lcapra Просто вызовите его, указав каталог, который нужно удалить, в качестве первого аргумента.
«Это быстро и эффективно с точки зрения памяти: нет стека рекурсии, нет необходимости запускать подпроцесс» - на самом деле это не так. В рекурсивной подстановке все еще продолжается рекурсия. Это также неэффективно с точки зрения памяти, потому что вы создаете два списка, содержащих пути ко всем файлам и папкам: встроенная функция sorted сначала создает список элементов, возвращаемых генератором glob, а затем создает новый список с отсортированными элементами. В зависимости от количества файлов это может привести к значительному потреблению памяти. О, и вы вводите сортировку с временной сложностью n log n.
@danzel, ты технически прав. Отредактирую свой ответ, чтобы не вводить в заблуждение.
@danzel сказал: я не думаю, что сортировка будет медленнее, чем многократный запуск подпроцесса для выполнения команд оболочки с использованием os.system или subprocess.run. Также память, необходимая для поддержки списка + отсортированный список, вероятно, меньше, чем память, необходимая для запуска подпроцесса и его запуска. YMMV
В моем случае единственным способом удаления было использование всех возможностей, потому что мой код должен был запускаться либо с помощью 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 и символические ссылки
Также обратите внимание, что даже если каталог был пуст, os.remove снова завершился бы ошибкой, потому что правильная функция - os.rmdir.