Python shutil.rmtree不';无法使用Windows库
因此,我正在构建一个简单的脚本,将某些文档备份到我的第二个硬盘(你永远不知道会发生什么!)。因此,我使用Python shutil.rmtree不';无法使用Windows库,python,windows,file,shutil,Python,Windows,File,Shutil,因此,我正在构建一个简单的脚本,将某些文档备份到我的第二个硬盘(你永远不知道会发生什么!)。因此,我使用shutil.copytree函数在第二个驱动器上复制数据。它工作得很好,这不是问题所在 如果目标已经存在,我使用shutil.rmtree函数删除树。我将向您展示我的代码: import shutil import os def overwrite(src, dest): if(not os.path.exists(src)): print(src, "does n
shutil.copytree
函数在第二个驱动器上复制数据。它工作得很好,这不是问题所在
如果目标已经存在,我使用shutil.rmtree
函数删除树。我将向您展示我的代码:
import shutil
import os
def overwrite(src, dest):
if(not os.path.exists(src)):
print(src, "does not exist, so nothing may be copied.")
return
if(os.path.exists(dest)):
shutil.rmtree(dest)
shutil.copytree(src, dest)
print(dest, "overwritten with data from", src)
print("")
overwrite(r"C:\Users\Centurion\Dropbox\Documents", r"D:\Backup\Dropbox Documents")
overwrite(r"C:\Users\Centurion\Pictures", r"D:\Backup\All Pictures")
print("Press ENTER to continue...")
input()
如您所见,这是一个简单的脚本。现在,当我第一次运行脚本时,一切都很好。图片和文档复制到myD:
硬盘上就可以了。但是,当我第二次运行时,这是我的输出:
C:\Users\Centurion\Programming\Python>python cpdocsnpics.py
D:\Backup\Dropbox Documents overwritten with data from C:\Users\Centurion\Dropbox\Documents
Traceback (most recent call last):
File "cpdocsnpics.py", line 17, in <module>
overwrite(r"C:\Users\Centurion\Pictures", r"D:\Backup\All Pictures")
File "cpdocsnpics.py", line 10, in overwrite
shutil.rmtree(dest)
File "C:\Python34\lib\shutil.py", line 477, in rmtree
return _rmtree_unsafe(path, onerror)
File "C:\Python34\lib\shutil.py", line 376, in _rmtree_unsafe
onerror(os.rmdir, path, sys.exc_info())
File "C:\Python34\lib\shutil.py", line 374, in _rmtree_unsafe
os.rmdir(path)
PermissionError: [WinError 5] Access is denied: 'D:\\Backup\\All Pictures'
C:\Users\Centurion\Programming\Python>Python-cpdocsnpics.py
D:\Backup\Dropbox文档被来自C:\Users\Centurion\Dropbox\Documents的数据覆盖
回溯(最近一次呼叫最后一次):
文件“cpdocsnpics.py”,第17行,在
覆盖(r“C:\Users\Centurion\Pictures”,r“D:\Backup\All Pictures”)
文件“cpdocsnpics.py”,第10行,处于覆盖状态
shutil.rmtree(目的地)
rmtree中第477行的文件“C:\Python34\lib\shutil.py”
返回树不安全(路径、错误)
文件“C:\Python34\lib\shutil.py”,第376行,在rmtree中
onerror(os.rmdir,path,sys.exc_info())
文件“C:\Python34\lib\shutil.py”,第374行,在rmtree中
os.rmdir(路径)
PermissionError:[WinError 5]访问被拒绝:“D:\\Backup\\All Pictures”
只有在我第一次复制图片时才会发生错误;我想这和图书馆有关
我该怎么办?这是一个跨平台的一致性问题。
您已使用readonly
属性复制了文件/dir。第一次“dest
”不存在,因此不执行rmtree方法。但是,当您尝试运行“overwrite”函数时,我们可以注意到“dest”位置存在(及其子树),但它是通过只读访问进行复制的。所以我们有个问题。
为了“修复”问题,必须为的onerror参数提供处理程序。只要您的问题是关于只读问题,解决方法就有点像这样:
def readonly_handler(func, path, execinfo):
os.chmod(path, 128) #or os.chmod(path, stat.S_IWRITE) from "stat" module
func(path)
正如您在python文档中看到的,onerror必须是可调用的,它接受三个参数:function、path和excinfo。欲了解更多信息
当然,这个处理程序是简单而具体的,但是如果发生其他错误,将引发新的异常,并且这个处理程序可能无法修复它们
注意:
Tim Golden(Python for windows contributor)一直在修补shutil.rmtree问题,它似乎将在Python3.5中得到解决(请参阅)。我在windows上使用shutil.rmtree
发现了一个只读文件以外的问题(在windows 7上测试)。我使用了shutil.rmtree
和shutil.copytree
的组合来在测试套件中创建一个测试夹具,因此序列在短时间内被反复调用(如果您以管理员身份运行脚本是否有效?@CodyPiersall No:Darn!我已经对您的问题投了赞成票,但我恐怕只能这样做:(.另请参见:和,它们至少是部分重复项(尽管描述和标记不太有用)。对这些问题的回答帮助我得到了下面发布的附加答案。可能是有趣的重复!所有函数是否都有onerror
处理程序?@Ken这取决于它!您的特殊错误是由于在本例中为只读文件的访问错误。只要您无法预测是否将使用“只读”复制您的文件属性设置,以便我建议您将回调(作为只读处理程序)传递给shutil.rmtree
def overwrite(src, dest):
if(not os.path.exists(src)):
print(src, "does not exist, so nothing may be copied.")
return
if(os.path.exists(dest)):
shutil.rmtree(dest, onerror=readonly_handler)
shutil.copytree(src, dest)
print(dest, "overwritten with data from", src)
print("")
def removetree(tgt):
def error_handler(func, path, execinfo):
e = execinfo[1]
if e.errno == errno.ENOENT or not os.path.exists(path):
return # path does not exist - treat as success
if func in (os.rmdir, os.remove) and e.errno == errno.EACCES:
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
func(path) # read-only file; make writable and retry
raise e
tmp = os.path.join(os.path.dirname(tgt),"_removetree_tmp")
os.rename(tgt, tmp)
shutil.rmtree(tmp, onerror=error_handler)
return
def removetree(tgt):
def error_handler(func, path, execinfo):
# figure out recovery based on error...
e = execinfo[1]
if e.errno == errno.ENOENT or not os.path.exists(path):
return # path does not exist
if func in (os.rmdir, os.remove) and e.errno == errno.EACCES:
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
func(path) # read-only file; make writable and retry
raise e
# Rename target directory to temporary value, then remove it
count = 0
while count < 10: # prevents indefinite loop
count += 1
tmp = os.path.join(os.path.dirname(tgt),"_removetree_tmp_%d"%(count))
try:
os.rename(tgt, tmp)
shutil.rmtree(tmp, onerror=error_handler)
break
except OSError as e:
time.sleep(1) # Give file system some time to catch up
if e.errno in [errno.EACCES, errno.ENOTEMPTY]:
continue # Try another temp name
if e.errno == errno.EEXIST:
shutil.rmtree(tmp, ignore_errors=True) # Try to clean up old files
continue # Try another temp name
if e.errno == errno.ENOENT:
break # 'src' does not exist(?)
raise # Other error - propagate
return
def renametree_temp(src):
"""
Rename tree to temporary name, and return that name, or
None if the source directory does not exist.
"""
count = 0
while count < 10: # prevents indefinite loop
count += 1
tmp = os.path.join(os.path.dirname(src),"_removetree_tmp_%d"%(count))
try:
os.rename(src, tmp)
return tmp # Success!
except OSError as e:
time.sleep(1)
if e.errno == errno.EACCES:
log.warning("util.renametree_temp: %s EACCES, retrying"%tmp)
continue # Try another temp name
if e.errno == errno.ENOTEMPTY:
log.warning("util.renametree_temp: %s ENOTEMPTY, retrying"%tmp)
continue # Try another temp name
if e.errno == errno.EEXIST:
log.warning("util.renametree_temp: %s EEXIST, retrying"%tmp)
shutil.rmtree(tmp, ignore_errors=True) # Try to clean up old files
continue # Try another temp name
if e.errno == errno.ENOENT:
log.warning("util.renametree_temp: %s ENOENT, skipping"%tmp)
break # 'src' does not exist(?)
raise # Other error: propagaee
return None
def removetree(tgt):
"""
Work-around for python problem with shutils tree remove functions on Windows.
See:
https://stackoverflow.com/questions/23924223/
https://stackoverflow.com/questions/1213706/
https://stackoverflow.com/questions/1889597/
http://bugs.python.org/issue19643
"""
# shutil.rmtree error handler that attempts recovery from attempts
# on Windows to remove a read-only file or directory (see links above).
def error_handler(func, path, execinfo):
e = execinfo[1]
if e.errno == errno.ENOENT or not os.path.exists(path):
return # path does not exist: nothing to do
if func in (os.rmdir, os.remove) and e.errno == errno.EACCES:
try:
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
except Exception as che:
log.warning("util.removetree: chmod failed: %s"%che)
try:
func(path)
except Exception as rfe:
log.warning("util.removetree: 'func' retry failed: %s"%rfe)
if not os.path.exists(path):
return # Gone, assume all is well
raise
if e.errno == errno.ENOTEMPTY:
log.warning("util.removetree: Not empty: %s, %s"%(path, tgt))
time.sleep(1)
removetree(path) # Retry complete removal
return
log.warning("util.removetree: rmtree path: %s, error: %s"%(path, repr(execinfo)))
raise e
# Try renaming to a new directory first, so that the tgt is immediately
# available for re-use.
tmp = renametree_temp(tgt)
if tmp:
shutil.rmtree(tmp, onerror=error_handler)
return