如何创建可由子进程读取的临时文件?

时间:2013-03-02 00:18:13

标签: python windows temporary-files

我正在编写一个需要将一些数据写入临时文件的Python脚本,然后创建一个运行C ++程序的子进程来读取临时文件。我正在尝试使用NamedTemporaryFile,但根据文档,

  

这个名称是否可以用来第二次打开文件,而命名的临时文件仍然是打开的,因此不同平台(它可以在Unix上使用;它不能在Windows NT或更高版本上使用)。

事实上,在Windows上,如果我在写入后刷新临时文件,但是在我希望它消失之前不要关闭它,则子进程无法打开它进行读取。

我正在通过使用delete=False创建文件,在生成子进程之前将其关闭,然后在完成后手动删除它来解决此问题:

fileTemp = tempfile.NamedTemporaryFile(delete = False)
try:
    fileTemp.write(someStuff)
    fileTemp.close()
    # ...run the subprocess and wait for it to complete...
finally:
    os.remove(fileTemp.name)

这似乎不优雅。有一个更好的方法吗?也许是一种打开临时文件权限的方法,以便子进程能够获得它?

4 个答案:

答案 0 :(得分:24)

由于没有其他人似乎有兴趣将这些信息公之于众......

tempfile确实公开了一个函数mkdtemp(),它可以轻视这个问题:

try:
    temp_dir = mkdtemp()
    temp_file = make_a_file_in_a_dir(temp_dir)
    do_your_subprocess_stuff(temp_file)
    remove_your_temp_file(temp_file)
finally:
    os.rmdir(temp_dir)

我将中间函数的实现留给读者,因为人们可能希望做一些事情,比如使用mkstemp()来加强临时文件本身的安全性,或者在删除之前就地覆盖文件它。我并不特别知道通过仔细阅读tempfile的来源,可能有哪些安全限制是不容易计划的。

无论如何,是的,在Windows上使用NamedTemporaryFile可能不够优雅,我的解决方案也可能不够优雅,但您已经确定Windows支持比优雅代码更重要,所以你不妨去领先并做一些可读的事情。

答案 1 :(得分:22)

According致Richard Oudkerk

  

(...)尝试重新打开NamedTemporaryFile的唯一原因是失败   Windows是因为当我们重新打开时,我们需要使用O_TEMPORARY

他举了一个如何在Python 3.3 +

中执行此操作的示例
import os, tempfile

DATA = b"hello bob"

def temp_opener(name, flag, mode=0o777):
    return os.open(name, flag | os.O_TEMPORARY, mode)

with tempfile.NamedTemporaryFile() as f:
    f.write(DATA)
    f.flush()
    with open(f.name, "rb", opener=temp_opener) as f:
        assert f.read() == DATA

assert not os.path.exists(f.name)

因为Python 2.x中的内置opener中没有open()参数,我们必须结合较低级os.open()os.fdopen()函数才能实现相同效果:

import subprocess
import tempfile

DATA = b"hello bob"

with tempfile.NamedTemporaryFile() as f:
    f.write(DATA)
    f.flush()

    subprocess_code = \
    """import os
       f = os.fdopen(os.open(r'{FILENAME}', os.O_RDWR | os.O_BINARY | os.O_TEMPORARY), 'rb')
       assert f.read() == b'{DATA}'
    """.replace('\n', ';').format(FILENAME=f.name, DATA=DATA)

    subprocess.check_output(['python', '-c', subprocess_code]) == DATA

答案 2 :(得分:12)

你可以随时进入低级,但不确定它是否足够干净:

fd, filename = tempfile.mkstemp()
try:
    os.write(fd, someStuff)
    os.close(fd)
    # ...run the subprocess and wait for it to complete...
finally:
    os.remove(filename)

答案 3 :(得分:9)

至少如果使用现有的Python库打开临时文件,则在Windows的情况下无法从多个进程访问它。根据{{​​3}},您可以指定第3个参数(dwSharedMode)共享模式标记FILE_SHARE_READCreateFile()函数:

  

启用文件或设备上的后续打开操作以请求读取   访问。否则,其他进程无法打开文件或设备   他们要求读取权限。如果未指定此标志,则指定该文件   或者设备已打开以进行读取访问,该功能失败。

因此,您可以编写Windows特定的C例程来创建自定义临时文件打开器函数,从Python调用它,然后您可以让您的子进程访问该文件而不会出现任何错误。但我认为你应该坚持使用现有的方法,因为它是最便携的版本,可以在任何系统上运行,因此是最优雅的实现。

  • 可以找到关于Linux和Windows文件锁定的讨论MSDN

编辑:结果可以打开&从Windows中的多个进程读取临时文件。见Piotr Dobrogost的here