【问题标题】:Force Overwrite in Os.Rename在 Os.Rename 中强制覆盖
【发布时间】:2011-11-12 20:30:59
【问题描述】:

如果另一个文件已经存在,是否可以强制重命名 os.rename 覆盖另一个文件?例如,在下面的代码中,如果文件 Tests.csv 已经存在,它将被 Tests.txt 文件(也重命名为 Tests.csv)替换。

os.rename("C:\Users\Test.txt","C:\Users\Tests.csv");

【问题讨论】:

  • 先取消链接目标文件,捕获潜在异常如何?
  • 记住总是在字符串中转义反斜杠(例如使用"C:\\Users\\Test.txt"
  • ...或使用r"C:\Users\Test.txt",但要小心r"C:\\"

标签: python


【解决方案1】:

从 Python 3.3 开始,现在有一个标准的跨平台解决方案,os.replace

重命名 文件或目录 src 到 dst。如果 dst 是一个目录,OSError 将是 提高。 如果 dst 存在并且是一个文件,它将被静默替换 用户有权限。如果 src 和 dst 打开,操作可能会失败 不同的文件系统。如果成功,重命名将是原子的 操作(这是 POSIX 要求)。

可用性:Unix、Windows。

3.3 版中的新功能。

但是,与文档相反,在 Windows 上它不能保证是原子的(在 Python 3.4.4 中)。那是因为internally 在 Windows 上使用了MoveFileEx,它没有做出这样的保证。

【讨论】:

  • MoveFileEx 怎么不是原子的?
  • @paulm 如果你查看它的 MSDN 页面,它从不承诺原子性,甚至明确建议 MoveFileTransacted 作为替代方案。实际上,MoveFileEx 在本地文件系统上是原子的,但在网络文件系统上是非原子的(嗯,实际上它取决于服务器)。但即使对于本地 FS,它的原子性也是非契约性的。
  • 大家都认为它是原子的,但没人愿意赌它?
【解决方案2】:

你可以试试shutil.move():

from shutil import move

move('C:\\Users\\Test.txt', 'C:\\Users\\Tests.csv')

或者os.remove,然后shutil.move

from os import remove
from shutil import move

remove('C:\\Users\\Tests.csv')
move('C:\\Users\\Test.txt', 'C:\\Users\\Tests.csv')

【讨论】:

  • @JohnZwinck:不,这适用于 Windows,而 os.rename 不适用。见shutil.move source code
  • 好吧,我为当前的答案 +1,尽管我怀疑这可能会导致竞争条件。从其他答案中,我认为这在 Windows 上是不可避免的。
  • 问题问“...如果存在...”,所以 remove 应该用 if 或 try 逻辑包装
【解决方案3】:

正如documentation 所说,如果文件存在,则无法保证在 Windows 上进行原子重命名操作,因此 Python 所做的是要求自己执行双重步骤 os.remove + os.rename,以处理潜在的错误。

在 unix 系统上,rename 覆盖目标(如果存在)(因为保证操作是原子的)。

请注意,在 Windows 上,即使您有权限,删除目标文件也可能会失败,因为该文件可能正在使用中。这是windows文件系统的另一个本质限制,你必须在代码中自己处理。

【讨论】:

    【解决方案4】:

    在 Unix 上,如果 dst 存在并且是一个文件,如果用户有权限,它将被静默替换。如果 src 和 dst 在不同的文件系统上,该操作可能会在某些 Unix 风格上失败。如果成功,重命名将是一个原子操作(这是 POSIX 要求)。 在 Windows 上,如果 dst 已经存在,即使是文件也会引发 OSError;当 dst 命名现有文件时,可能无法实现原子重命名http://docs.python.org/library/os.html#os.rename

    【讨论】:

    • Windows 应该被逐出地球的另一个原因
    • 或者不是因为这完全错误,MoveFile API 是原子的
    【解决方案5】:

    有趣的是,os.rename() 的文档说它确实替换了 Unix 系统上的目标,但在 Windows 上却没有。他们模糊地提到如果目标存在于 Windows 上就不可能实现原子重命名,IMO 几乎没有足够的理由不支持它。

    我想你应该捕获 OSError(目标存在于 Windows 上)并删除目标并重试。

    【讨论】:

      【解决方案6】:

      来自标准库文档,“在 Windows 上,如果 dst 已经存在,即使是文件也会引发 OSError;当 dst 命名现有文件时,可能无法实现原子重命名。”

      http://docs.python.org/library/os.html#os.rename

      不幸的是,唯一的解决办法就是更换操作系统; Windows 只是不允许在现有文件顶部使用 rename()

      【讨论】:

        【解决方案7】:

        如何使用 replace() 和 shutil.move() ? 示例:

        import os
        from shutil import move
        
        filename=r'C:\Users\Test.txt'
        move(filename,filename.replace('.txt','.csv')
        

        您还可以使其对所有文件更通用。 谢谢

        【讨论】:

          【解决方案8】:
          import os
          try:
            os.rename("/path/input file", "/path/output file")
          except FileExistsError:
            os.remove("/path/output file")
            os.rename("/path/input file", "/path/output file")
          

          【讨论】:

            【解决方案9】:

            accepted answer 的语法(对于 Python >= 3.3):

            os.replace("src/file/path", "dst/file/path")
            

            (文档:os.replace

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-12-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-01-11
              相关资源
              最近更新 更多