При попытке удалить папку, которая не пуста, я получаю ошибку "доступ запрещен". В моей попытке я использовал следующую команду: os.remove("/folder_name")
.
Каков наиболее эффективный способ удаления/удаления папки/каталога, который не пуст?
При попытке удалить папку, которая не пуста, я получаю ошибку "доступ запрещен". В моей попытке я использовал следующую команду: os.remove("/folder_name")
.
Каков наиболее эффективный способ удаления/удаления папки/каталога, который не пуст?
import shutil
shutil.rmtree('/folder_name')
Стандартная справочная библиотека: shutil.rmtree.
По дизайну rmtree
выходит из строя на деревьях папок, содержащих файлы только для чтения. Если вы хотите, чтобы папка удалялась независимо от того, содержит ли она файлы только для чтения, используйте
shutil.rmtree('/folder_name', ignore_errors=True)
От документы 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))
import shutil
shutil.rmtree(dest, ignore_errors=True)
из 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 dir content, remove this line
где pth
является экземпляром pathlib.Path
. Хороший, но не самый быстрый.
В этом примере показано, как удалить дерево каталогов в Windows, где для некоторых файлов установлен бит только для чтения. Он использует обратный вызов onerror, чтобы очистить бит readonly и повторить попытку удаления. Любой последующий сбой будет распространяться.
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)
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 является ложным, а onerror - None, здесь возникает исключение. Здесь вводится код
если вы уверены, что хотите удалить все дерево dir, и больше не интересуетесь содержимым dir, тогда обход для всего дерева dir - это глупость... просто вызовите команду native OS из 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])
Основываясь на ответе 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")
Просто некоторые варианты 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")
Если вы не хотите использовать модуль 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
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)
Для простоты вы можете использовать команду os.system:
import os
os.system("rm -rf dirname")
Как очевидно, он фактически вызывает системный терминал для выполнения этой задачи.
Чтобы удалить папку, даже если она может не существовать (избегая условия гонки в ответ Чарльза Чоу), но все еще есть ошибки, когда другие вещи идут не так (например, проблемы с разрешением, ошибка чтения диска, файл не является каталогом)
Для 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)
С os.walk я бы предложил решение, которое состоит из 3 однострочных вызовов 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.
Десять лет спустя и с использованием 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 для явной обработки непустых директорий.
Я хотел бы добавить "чистый путь пути":
from pathlib import Path
from typing import Union
def del_dir(target: Union[Path, str], only_if_empty: bool = False):
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)Я нашел очень простой способ удалить любую папку (даже НЕ пустую) или файл в ОС Windows.
os.system('powershell.exe rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)
Для 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.