如何在Python中的Windows上创建命名临时文件?

时间:2010-03-30 23:23:07

标签: python windows temporary-files

我有一个Python程序需要创建一个命名的临时文件,该文件将在程序过程中打开和关闭几次,并且应该在程序退出时删除。不幸的是,tempfile中的所有选项似乎都不起作用:

  • TemporaryFile没有可见名称
  • NamedTemporaryFile创建一个类似文件的对象。我只需要一个文件名。我已经尝试关闭它返回的对象(在设置delete = False之后),但是当我稍后尝试打开文件时出现流错误。
  • SpooledTemporaryFile没有可见名称
  • mkstemp返回打开的文件对象和名称;它不保证在程序退出时删除文件
  • mktemp返回文件名,但不保证在程序退出时删除文件

我尝试在上下文管理器中使用mktemp 1 ,如下所示:

def get_temp_file(suffix):
    class TempFile(object):
        def __init__(self):
            self.name = tempfile.mktemp(suffix = '.test')

        def __enter__(self):
            return self

        def __exit__(self, ex_type, ex_value, ex_tb):
            if os.path.exists(self.name):
                try:
                    os.remove(self.name)
                except:
                    print sys.exc_info()

     return TempFile()

...但是这给了我一个WindowsError(32, 'The process cannot access the file because it is being used by another process')。文件名由我的程序生成的进程使用,即使我确保在退出之前进程完成,但似乎有一个不受我控制的竞争条件。

处理此问题的最佳方法是什么?

1 我不需要担心这里的安全问题;这是测试模块的一部分,所以最邪恶的人可能会导致我们的单元测试虚假失败。惊恐的事件!

4 个答案:

答案 0 :(得分:4)

今天我需要类似的东西,最后写下自己的东西。我正在使用atexit.register()来注册一个函数回调,该函数回调在程序退出时删除文件。

请注意,此编码标准与典型的Python编码标准(camelCase而非using_underscores)略有不同。当然,随意调整。

def temporaryFilename(prefix=None, suffix='tmp', dir=None, text=False, removeOnExit=True):
    """Returns a temporary filename that, like mkstemp(3), will be secure in
    its creation.  The file will be closed immediately after it's created, so
    you are expected to open it afterwards to do what you wish.  The file
    will be removed on exit unless you pass removeOnExit=False.  (You'd think
    that amongst the myriad of methods in the tempfile module, there'd be
    something like this, right?  Nope.)"""

    if prefix is None:
        prefix = "%s_%d_" % (os.path.basename(sys.argv[0]), os.getpid())

    (fileHandle, path) = tempfile.mkstemp(prefix=prefix, suffix=suffix, dir=dir, text=text)
    os.close(fileHandle)

    def removeFile(path):
        os.remove(path)
        logging.debug('temporaryFilename: rm -f %s' % path)

    if removeOnExit:
        atexit.register(removeFile, path)

    return path

超级基本测试代码:

path = temporaryFilename(suffix='.log')
print path
writeFileObject = open(path, 'w')
print >> writeFileObject, 'yay!'
writeFileObject.close()

readFileObject = open(path, 'r')
print readFileObject.readlines()
readFileObject.close()

答案 1 :(得分:2)

当我需要使用csv模块将上传的文件保存到打开的临时文件时,我遇到了完全相同的问题。最令人恼火的是WindowsError中的文件名指向临时文件,但将上传文件内容保存到StringIO缓冲区并将缓冲区数据推送到临时文件中解决了问题。因为我的需求足够,因为上传的文件总是适合内存。

问题出现在我通过Apache的CGI上传了一个带脚本的文件时,当我从控制台运行类似的脚本时,我无法重现问题。

答案 2 :(得分:1)

如果您不关心安全性有什么问题吗?

tmpfile_name = tempfile.mktemp()
# do stuff
os.unlink(tmpfile_name)

你可能会试图过度设计这个。如果要确保在程序退出时始终删除此文件,可以将main()执行包装在try/finally中。保持简单!

if __name__ == '__main__':
    try:
        tmpfile_name = tempfile.mktemp()
        main()
    except Whatever:
        # handle uncaught exception from main()
    finally:
        # remove temp file before exiting
        os.unlink(tmpfile_name)

答案 3 :(得分:0)

如何创建一个临时目录,然后在该目录中创建一个静态文件名?从上下文退出后,目录和文件将被删除。

with tempfile.TemporaryDirectory() as directory_name:
  filename = os.path.join(directory_name, 'file' + suffix)
  # use the filename to open a file for writing, or run a os.system() command, etc.