【问题标题】:Why can't my file handler's file within a temporary directory be cleaned up on Windows?为什么不能在 Windows 上清理临时目录中的文件处理程序的文件?
【发布时间】:2020-05-07 01:09:08
【问题描述】:

我有一些代码在 unix 系统上运行良好,但在 Windows 上却不行。我想让它跨平台,但我的头撞到了墙上。最小复制如下:

文件 1:foo.py

import os
import sys
import logging

logging.basicConfig(level=logging.INFO, stream=sys.stdout)
logger = logging.getLogger('foo')

def main(dir):
    logger.addHandler(logging.FileHandler(
        os.path.join(dir, 'temporary.log')
    ))

    logger.info("Hello, world!")

文件 2:main.py

from foo import main

import tempfile

if __name__ == "__main__":
    with tempfile.TemporaryDirectory("test") as tmp:
        main(tmp)

我希望创建临时目录,在其中创建一个文件,将向其发出日志,然后在tmp 超出范围时清理两者。

相反,Windows 提供了一个错误:

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: '...'

我尝试将FileHandler 的模式从附加模式更改为远离附加模式,我尝试手动清理文件和目录,我尝试将文件从创建延迟到登录并启动日志级别,我什至尝试在 foo.main 中实例化记录器,希望不会持续存在对处理程序的引用——无论如何,我仍然看到这个错误。

我该如何解决这个问题?

【问题讨论】:

  • "temporary.log" 打开而不删除共享。即使它确实共享删除访问权限,只要日志处理程序引用该文件,“已删除”文件实际上仍会链接在目录中。 (在当前版本的 Windows 10 中,它将是未链接的 POSIX 样式,但您不能假设这一点。)这反过来会导致清理临时目录失败,因为它不会为空。
  • main 函数可以保留对处理程序的引用以在 finally 块中调用 logger.removeHandler(handler)。这将确保文件在main 返回之前关闭。

标签: python windows logging file-permissions temporary-directory


【解决方案1】:

您需要关闭处理程序,它会关闭文件。然后删除临时目录应该可以工作。我做了如下修改:

# foo.py
import os
import sys
import logging

logging.basicConfig(level=logging.INFO, stream=sys.stdout)
logger = logging.getLogger('foo')

def main(dir):
    h = logging.FileHandler(os.path.join(dir, 'temporary.log'))
    logger.addHandler(h)
    logger.info("Hello, world!")
    logger.removeHandler(h)
    return h

# main.py
from foo import main

import tempfile

if __name__ == "__main__":
    with tempfile.TemporaryDirectory("test") as tmp:
        print('Using temp dir %s' % tmp)
        h = main(tmp)
        h.close()

接下来,它似乎工作:

~> python3 c:\temp\main.py
Using temp dir C:\Users\Vinay\AppData\Local\Temp\tmp60qirkhutest
INFO:foo:Hello, world!

~> dir AppData\Local\Temp\tmp60qirkhutest
 Volume in drive C has no label.
 Volume Serial Number is D195-0C0D

 Directory of C:\Users\Vinay\AppData\Local\Temp

File Not Found

如果您注释掉 h.close() 行,它会像以前一样失败。

【讨论】:

  • 当处理程序在main 中被删除并超出范围时(假设 OP 的代码不返回处理程序),文件在 CPython 中自动关闭——至少它在我的测试,虽然我没有检查代码。您可以明确地关闭它以确定。但是删除处理程序肯定需要在finally 块中,以确保在出现未处理的异常时清理临时目录不会失败。
  • @ErykSun 我实际上尝试 not 返回处理程序,只是将其删除并在 finally 块中关闭它,但由于某种原因这不起作用......我以某种方式认为范围界定会为我处理这个问题。
  • @erip,对我来说效果很好。关闭是关闭的。除了作为将控制权交还给调用者的一般手段之外,我认为没有任何理由必须返回处理程序。
  • 只是告诉你我看到了什么。 :-)
  • 没有理由特别返回处理程序,我只是用它来说明解决问题的一种方法。这不一定是最好的方法,但我认为 OP 的脚本只是说明问题的一种方式,并以这种精神解决了我的变化。此外,打开的处理程序保存在内部列表中,并且在超出范围时不一定关闭。
猜你喜欢
  • 2014-05-07
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多