Сбой shutil.rmtree в Windows с «Доступ запрещен» - PullRequest
58 голосов
/ 17 апреля 2010

В Python при запуске shutil.rmtree над папкой, содержащей файл только для чтения, выводится следующее исключение:

 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 221, in rmtree
   onerror(os.remove, fullname, sys.exc_info())
 File "C:\Python26\lib\shutil.py", line 219, in rmtree
   os.remove(fullname)
WindowsError: [Error 5] Access is denied: 'build\\tcl\\tcl8.5\\msgs\\af.msg'

Просматривая диалоговое окно «Свойства файла», я заметил, что файл af.msg установлен только для чтения.

Таким образом, вопрос заключается в следующем: что такое самый простой обходной путь / исправление, чтобы обойти эту проблему - учитывая, что я намерен сделать эквивалент rm -rf build/, но на Windows? (без использования сторонних инструментов, таких как unxutils или cygwin - так как этот код предназначен для запуска на чистой установке Windows с Python 2.6 с установленным PyWin32)

Ответы [ 5 ]

78 голосов
/ 17 апреля 2010

Проверьте этот вопрос:

Какой пользователь запускает скрипты Python, как в Windows?

Очевидно, ответ заключается в том, чтобы изменить файл / папку, чтобы она не была доступна только для чтения, а затем удалить ее.

Вот обработчик onerror() из pathutils.py, упомянутый @Sridhar Ratnakumar в комментариях:

def onerror(func, path, exc_info):
    """
    Error handler for ``shutil.rmtree``.

    If the error is due to an access error (read only file)
    it attempts to add write permission and then retries.

    If the error is for another reason it re-raises the error.

    Usage : ``shutil.rmtree(path, onerror=onerror)``
    """
    import stat
    if not os.access(path, os.W_OK):
        # Is the error an access error ?
        os.chmod(path, stat.S_IWUSR)
        func(path)
    else:
        raise
23 голосов
/ 17 апреля 2010

Я бы сказал, реализовать ваше собственное дерево rmt с os.walk , которое обеспечивает доступ с помощью os.chmod к каждому файлу перед попыткой его удаления.

Как-то так (не проверено):

import os
import stat

def rmtree(top):
    for root, dirs, files in os.walk(top, topdown=False):
        for name in files:
            filename = os.path.join(root, name)
            os.chmod(filename, stat.S_IWUSR)
            os.remove(filename)
        for name in dirs:
            os.rmdir(os.path.join(root, name))
    os.rmdir(top)      
12 голосов
/ 10 июня 2011

Ну, помеченное решение не работает для меня ... сделал это вместо этого:

os.system('rmdir /S /Q "{}"'.format(directory))
0 голосов
/ 20 ноября 2015

Простой обходной путь использует subprocess.call

from subprocess import call
call("rm -rf build/", shell=True)

Для того, чтобы выполнить все, что вы хотите.

0 голосов
/ 12 февраля 2015
shutil.rmtree(path,ignore_errors=False,onerror=errorRemoveReadonly) 
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

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

...