12

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

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

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

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

4 回答 4

5

我今天需要类似的东西,最后写了我自己的。我正在使用 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()
于 2011-03-24T17:15:36.500 回答
2

I have had exactly the same problem when I needed to save an uploaded file to the opened temporary file using the csv module. The most irritating thing was that the filename in WindowsError pointed to the temporary file, but saving the uploading file contents into the StringIO buffer and pushing the buffer data into the temporary file fixed the problem. For my needs that was enough since uploaded files always fit in memory.

The problem was only when I uploaded a file with a script through Apache's CGI, when I ran the similar script from console I could not reproduce the problem though.

于 2010-04-02T11:14:54.380 回答
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)
于 2010-03-31T00:04:48.667 回答
1

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

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.
于 2019-09-04T05:05:26.327 回答