Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python shutil.rmtree不';无法使用Windows库_Python_Windows_File_Shutil - Fatal编程技术网

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()
如您所见,这是一个简单的脚本。现在,当我第一次运行脚本时,一切都很好。图片和文档复制到my
D:
硬盘上就可以了。但是,当我第二次运行时,这是我的输出:

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