【问题标题】:Renaming temporary files in Python在 Python 中重命名临时文件
【发布时间】:2021-08-25 09:09:22
【问题描述】:

我想做以下事情。创建一个临时文件并处理它。如果成功,将其重命名为真实文件。如果失败,则删除该文件。

我尝试了以下方法:

with tempfile.NamedTemporaryFile(dir=os.getcwd()) as f:
    f.write(b'foobar')
    f.delete = False
    f.flush()
    os.rename(f.name, 'foobar')

但是,当它试图删除它时,我仍然得到一个文件不存在的异常。我可能会使用 try-catch 来忽略此错误,但这会很丑陋,并且也可能会忽略其他错误。或者我可以使用mkstemp() 并自己管理删除,但这有一个问题,它返回的是文件描述符而不是文件对象,而且我找不到从文件描述符创建文件对象的方法。

这个问题有什么合适的解决办法吗?

【问题讨论】:

  • “我尝试删除文件时仍然收到文件不存在的异常”因为你重命名了它?
  • @DeepSpace:是的。问题是如何避免这种情况。
  • @petersohn:您需要 Windows 支持吗?
  • 你不知道os.fdopen

标签: python temporary-files


【解决方案1】:

初始化时需要传递delete=False,后面设置f.delete = False是不行的。使用此代码编写后,我能够重命名它:

with tempfile.NamedTemporaryFile(dir=os.getcwd(), delete=False) as f:
    f.write(b'foobar')
    f.flush()
    os.rename(f.name, 'foobar')

我查看了Lib/tempfile.py 的代码来确认这种行为。

当您调用NamedTemporartyFile 时,它会初始化并返回在同一文件中定义的_TemporaryFileWrapper 类的实例。看看这个类的__init__()

def __init__(self, file, name, delete=True):
        self.file = file
        self.name = name
        self.delete = delete
        self._closer = _TemporaryFileCloser(file, name, delete)

这是_TemporaryFileCloser类的__init__()

def __init__(self, file, name, delete=True):
        self.file = file
        self.name = name
        self.delete = delete

当您退出 with 语句时,在关闭文件期间,检查 _TemporaryFileCloserself.delete 属性。当您执行f.delete = False 时,您更改了_TemporaryFileWrapper 类的self.delete 属性,而不是_TemporaryFileCloser 类。因此,即使在开发人员端看起来像这样,关闭行为也不会改变。所以你必须在初始化期间在with 语句中传递delete=False,就像我的代码示例一样。

如果还想修改行为,可以访问self._closer属性,不过会有点丑。

with tempfile.NamedTemporaryFile(dir=os.getcwd()) as f:
    f.write(b'foobar')
    f.flush()
    f._closer.delete = False
    os.rename(f.name, 'foobar')

顺便说一句,我在 Windows 10 上的 Ubuntu WSL 上执行了此操作。我不确定您使用的是哪个操作系统,这可能会影响行为。

【讨论】:

  • 一开始我通过了delete=True,因为我希望它在出现错误时删除文件。但我想我需要手动删除它。
【解决方案2】:

这可以通过NamedTemporaryFile 类来实现。关闭后,您可以将其移动到所需的位置/文件名。您需要在移动之前关闭文件以避免删除错误。

from tempfile import NamedTemporaryFile
import shutil

with NamedTemporaryFile(delete=False) as tmp:
    tmp.write(b'hi')

# move file to target location/name
shutil.move(tmp.name, 'target')

【讨论】:

  • 我不认为记录在案的 Windows 问题会阻止这种使用在 Windows 上运行——即使在 Windows 上也应该只需要在移动之前关闭文件。另外,这里的关键部分是delete=FalseNamedTemporaryFile 已经在问题中了)。
  • 我曾经试图让它工作。删除设置都不会让我关闭文件(因为这是执行文件所必需的,否则会出现文件繁忙错误)并在 with 块退出时删除文件。
  • @DanD。你试过上面的代码吗?这个对我有用。如果文件在关闭时被删除,则无法再将其移动到新位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
  • 2018-08-17
  • 1970-01-01
  • 2022-11-27
  • 2013-05-07
相关资源
最近更新 更多