如何在Windows中使用Python创建命名临时文件?
我有一个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, '该进程无法访问文件,因为它正被另一个进程使用')
的错误。这个文件名被我程序启动的一个进程使用,尽管我确保这个进程在退出前完成,但似乎出现了我无法控制的竞争条件。
处理这个问题的最佳方法是什么?
1在这里我不需要担心安全问题;这是一个测试模块的一部分,所以最坏的情况就是让我们的单元测试偶尔失败。真可怕!
5 个回答
2
我遇到过完全一样的问题,当我需要用csv模块把上传的文件保存到打开的临时文件时。最让人烦恼的是,WindowsError中的文件名指向了临时文件,但我把上传文件的内容先保存到StringIO这个缓冲区,然后再把缓冲区的数据写入临时文件,这样就解决了问题。对我来说,这样就足够了,因为上传的文件总是能放进内存里。
这个问题只发生在我通过Apache的CGI上传文件时,当我从控制台运行类似的脚本时却没有遇到这个问题。
3
你可以先创建一个临时文件夹,然后在这个文件夹里创建一个固定名字的文件。当你退出这个环境时,这个文件夹和里面的文件都会被删除。
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.
5
今天我需要做类似的事情,最后自己写了一个。 我使用了 atexit.register() 这个功能来注册一个回调函数,这个函数会在程序退出时删除文件。
需要注意的是,这里的编码标准和一般的 Python 编码标准稍微有点不同(用驼峰命名法,而不是用下划线)。当然,你可以根据自己的需要进行调整。
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()