没有写权限时,Python tempfile.TemporaryFile在Windows上挂起

时间:2019-03-11 19:31:33

标签: python-3.x windows temporary-files

我的环境是在Windows 10上运行的Python 3.7.2。我正在使用目录选择小部件,并且正在寻找最干净,最确定的方法来测试所选目录路径是否允许写特权。 / p>

以前,我是通过通常的open()方法打开一个命名文件的,向其中写入一些字节,然后删除它-将整个内容放入try-except块中。没关系,但是有留下不需要的文件的风险。最近,我翻阅了tempfile.TemporaryFile()的文档,这种似乎更干净的方法来获得相同的结果,而没有在系统上留下垃圾文件的风险。

问题是,当给tempfile.TemporaryFile()一个只读文件夹的参数时,dir挂在我的系统上。我在Google上四处搜寻,发现了this very old bug,但它是针对Python 2.4编写的,很久以前就已修复。

这是我拼凑来说明问题的测试脚本。 (请注意,我已经省略了实际应用程序执行的文件删除,因为它与插图无关。)

import os, tempfile

def normOpen(checkPath):
    try:
        with open(os.path.join(checkPath,'x.txt'),'wb') as tf:
            tf.write(b'ABC')
    except Exception as e:
        print('Write disabled for '+checkPath)
        print(str(e))
    else:
        print('Write enabled  for '+checkPath)

def tfOpen(checkPath):
    try:
        with tempfile.TemporaryFile(dir=checkPath) as tf:
            tf.write(b'ABC')
    except Exception as e:
        print('Write disabled for '+checkPath)
        print(str(e))
    else:
        print('Write enabled  for '+checkPath)

tryPath1 = 'C:\\JDM\\Dev_Python\\TMPV\\canwrite'  #Full control path
tryPath2 = 'C:\\JDM\\Dev_Python\\TMPV\\nowrite'   #Read-only path

print('First method - normal file-open')
normOpen(tryPath1)
normOpen(tryPath2)

print('Second method - TemporaryFile')
tfOpen(tryPath1)
tfOpen(tryPath2)

当我运行此脚本时,它挂在最后一行上,然后坐在那里(任务管理器显示Python消耗约10-15%的CPU)。

Windows CMD

有人知道这个问题可能是什么吗?特别是这是Python错误,还是我对TemporaryFile的使用有问题?

如果有帮助,以下是Windows为这些文件夹显示的特定特权:

Permissions

2 个答案:

答案 0 :(得分:1)

比我最初做的更深入的潜水,找到了答案。这确实是a Python bug,它是在一段时间前报道的,但有待解决。

eryksun 的评论描述了细节-这就是促使我仔细研究Python错误数据库的原因-最终这才是我们应得的。我只是在这里填写它,以便回答并结束问题。

该错误仅影响Windows环境,但不幸的是,该错误导致tempfile.TemporaryFile不能在Windows上用于此常见用例。

答案 1 :(得分:0)

我建议使用os.path.join(tempfile.gettempdir(), os.urandom(32).hex())替换NamedTemporaryFile的用法。

这是更安全,更快和跨平台的。仅在FAT或DOS系统上失败,对于大多数人而言,这不再是问题。

这是兼容版本:

import os, tempfile, gc


class TemporaryFile:
    def __init__(self, name, io, delete):
        self.name = name
        self.__io = io
        self.__delete = delete

    def __getattr__(self, k):
        return getattr(self.__io, k)

    def __del__(self):
        if self.__delete:
            os.unlink(self.name)


def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix='', prefix='tmp', dir=None, delete=True):
    if not dir:
        dir = tempfile.gettempdir()
    name = os.path.join(dir, prefix + os.urandom(32).hex() + suffix)
    fh = open(name, "w+b", bufsize)
    if mode != "w+b":
        fh.close()
        fh = open(name, mode)
    return TemporaryFile(name, fh, delete)

..这是一个带有测试的模块:

https://gist.github.com/earonesty/a052ce176e99d5a659472d0dab6ea361