2010-04-16 3 views
49

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

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 установлен)

+4

'shutil.rmtree' использует' os.remove' для удаления файлов. 'os.remove' удаляет только доступные для чтения файлы (по крайней мере, в Unix). 'os.remove' не может удалить файл в Windows, если он используется. – jfs

+0

Возможный дубликат [Удаление каталога в Python] (http://stackoverflow.com/questions/1889597/deleting-directory-in-python) – mozzbozz

ответ

63

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

What user do python scripts run as in 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 
+1

Хех. Я только что обнаружил обработчик 'onerror' на http://www.voidspace.org.uk/downloads/pathutils.py –

+0

.. обнаружил, что через http://trac.pythonpaste.org/pythonpaste/ticket/359 –

+1

Хотя комментарии для этого ответа состоят в том, что «изменить файл/папку, чтобы он не был доступен только для чтения», я все же получил доступ к файлам, доступным только для чтения. [This] (http://stackoverflow.com/a/1889686/116047) реализация работала, хотя. – Pakman

17

Я бы сказал, реализовать свой собственный rmtree с 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)  
+0

Это почти правильно - Windows поддерживает только 'stat.S_IWRITE' (это то, что вы хотите в любом случае) - http: // docs. python.org/library/os.html#os.chmod –

+0

Я проверил, что 'os.chmod (filename, stat.S_IWUSR)' удаляет флаг только для чтения, поэтому он работает на WinXP. И учитывая, что документы говорят о 'stat.S_IWRITE':« Синоним Unix V7 для S_IWUSR »(http://docs.python.org/library/stat.html#stat.S_IWRITE), я думаю, что мой код все равно. – Epcylon

+0

Отлично, с длинными файлами, которые слишком длинны, это кажется единственным способом. Рекомендация взять или изменить shutil.rmtree возможно. – Anthony

5

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

os.system('rmdir /S /Q "{}"'.format(directory)) 
0
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 является set, ошибки игнорируются; в противном случае, если установлен aterror , он вызывается для обработки ошибки с аргументами (func, path, exc_info), где func - os.listdir, os.remove или os.rmdir; Путь - это аргумент этой функции, которая привела к ее провалу; и exc_info - это кортеж, возвращаемый sys.exc_info(). Если ignore_errors ложно и OnError его нет, исключение составляет raised.enter код здесь

1

Простое решение использует subprocess.call

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

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