2010-04-16 15 views
49

In Python, quando si esegue shutil.rmtree su una cartella che contiene un file di sola lettura, la seguente eccezione viene stampato:shutil.rmtree non riesce su Windows con 'Accesso negato'

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' 

Guardando in Proprietà file dialogo Ho notato che il file af.msg è impostato per essere di sola lettura.

Quindi la domanda è: qual è il più semplice soluzione/fix per aggirare questo problema - dato che la mia intenzione è quella di fare un equivalente di rm -rf build/ ma su Windows? (Senza dover utilizzare strumenti di terze parti come UnxUtils o Cygwin - come questo codice è mirato per essere eseguito su un nudo installazione di Windows con Python 2.6 w/installato PyWin32)

+4

'shutil.rmtree' utilizza' os.remove' per rimuovere i file. 'os.remove' rimuove solo i file di sola lettura (almeno su Unix). 'os.remove' non può rimuovere il file su Windows se è in uso. – jfs

+0

possibile duplicato di [Eliminazione directory in Python] (http://stackoverflow.com/questions/1889597/deleting-directory-in-python) – mozzbozz

risposta

63

controllare questa domanda out:

What user do python scripts run as in windows?

Apparentemente la risposta è cambiare il file/cartella in modo che non sia di sola lettura e quindi rimuoverlo.

Ecco onerror() handler da pathutils.py citato da @Sridhar Ratnakumar nei commenti:

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

Heh. Ho appena scoperto il gestore 'onerror' su http://www.voidspace.org.uk/downloads/pathutils.py –

+0

.. ho scoperto che tramite http://trac.pythonpaste.org/pythonpaste/ticket/359 –

+1

Anche se i commenti per questo stato di risposta 'cambiano il file/cartella per non essere di sola lettura', ho ancora ricevuto l'accesso negato su cartelle di sola lettura. [This] (http://stackoverflow.com/a/1889686/116047) l'implementazione ha funzionato, però. – Pakman

17

direi implementare il proprio rmtree con os.walk che garantisce l'accesso utilizzando os.chmod su ogni file prima di tentare di eliminarlo.

Qualcosa di simile (non testata):

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

Questo è quasi corretto - Windows supporta solo 'stat.S_IWRITE' (che è quello che vuoi comunque) - http: // docs. python.org/library/os.html#os.chmod –

+0

Ho verificato che 'os.chmod (filename, stat.S_IWUSR)' ha rimosso il flag di sola lettura, quindi funziona su WinXP. E considerando questo è ciò che i documenti dicono su 'stat.S_IWRITE':" Sinonimo di Unix V7 per S_IWUSR "(http://docs.python.org/library/stat.html#stat.S_IWRITE), sto pensando al mio codice è giusto comunque. – Epcylon

+0

Ottimo, con percorsi di file troppo lunghi questo sembra l'unico modo. Una raccomandazione per impegnarsi o cambiare shutil.rmtree forse. – Anthony

5

Bene, la soluzione marcata non ha funzionato per me ... ha fatto questo, invece:

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 

Se ignore_errors è impostato, gli errori vengono ignorati; altrimenti, se è impostato onerror , viene chiamato per gestire l'errore con argomenti (func, path, exc_info) dove func è os.listdir, os.remove o os.rmdir; Il percorso è l'argomento di quella funzione che ha causato l'errore; e exc_info è una tupla restituita da sys.exc_info(). Se ignore_errors è falsa e onerror è Nessuno, un'eccezione è raised.enter codice qui

1

Una soluzione semplice sta usando subprocess.call

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

Al fine di eseguire tutto quello che volete.