如何从Python Pyramid中提供临时文件

MFB*_*MFB 8 python pyramid

目前,我只是提供这样的文件:

# view callable
def export(request):
    response = Response(content_type='application/csv')
    # use datetime in filename to avoid collisions
    f = open('/temp/XML_Export_%s.xml' % datetime.now(), 'r')
        # this is where I usually put stuff in the file
    response.app_iter = f
    response.headers['Content-Disposition'] = ("attachment; filename=Export.xml")
    return response
Run Code Online (Sandbox Code Playgroud)

这个问题是我无法关闭,甚至更好地在返回响应后删除该文件.该文件被孤立.我可以想到一些关于这方面的hacky方法,但我希望有一个标准的方法在那里.任何帮助都是极好的.

Mic*_*kel 10

您不希望将文件指针设置为app_iter.这将导致WSGI服务器逐行读取文件(与之相同for line in file),这通常不是控制文件上载的最有效方式(想象每行一个字符).Pyramid支持的文件服务方式是通过pyramid.response.FileResponse.您可以通过传递文件对象来创建其中一个.

response = FileResponse('/some/path/to/a/file.txt')
response.headers['Content-Disposition'] = ...
Run Code Online (Sandbox Code Playgroud)

另一种选择是将文件指针传递给对象,app_iter但将其包装在pyramid.response.FileIter对象中,该对象将使用合理的块大小来避免只是逐行读取文件.

WSGI规范有严格的要求,即在响应结束时调用包含close方法的响应迭代器.因此设置不应导致任何内存泄漏.双方并还支持方法,并因此将清理预期.response.app_iter = open(...)FileResponseFileIterclose

作为对这个答案的一个小更新,我想我会解释为什么FileResponse采用文件路径而不是文件指针.WSGI协议为服务器提供了一种可选功能,可以通过提供优化的机制来提供静态文件environ['wsgi.file_wrapper'].FileResponse如果您的WSGI服务器提供了该支持,它将自动处理此问题.考虑到这一点,您会发现将数据保存到ramdisk上的tmp文件并提供FileResponse完整路径,而不是尝试传递文件指针是一种胜利FileIter.

http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/api/response.html#pyramid.response.FileResponse

  • `FileResponse`不提供删除文件的任何支持.如果`NamedTemporaryFile`支持通过`close`方法删除底层文件,那么你可以将它包装在`FileIter`中. (2认同)

K Z*_*K Z 9

更新:

请参阅Michael Merickel的答案,以获得更好的解决方案和解释.

如果要在response返回文件后删除该文件,可以尝试以下操作:

import os
from datetime import datetime
from tempfile import NamedTemporaryFile

# view callable
def export(request):
    response = Response(content_type='application/csv')
    with NamedTemporaryFile(prefix='XML_Export_%s' % datetime.now(),
                            suffix='.xml', delete=True) as f:
        # this is where I usually put stuff in the file
        response = FileResponse(os.path.abspath(f.name))
        response.headers['Content-Disposition'] = ("attachment; filename=Export.xml")
        return response
Run Code Online (Sandbox Code Playgroud)

您可以考虑使用NamedTemporaryFile:

NamedTemporaryFile(prefix='XML_Export_%s' % datetime.now(), suffix='.xml', delete=True)
Run Code Online (Sandbox Code Playgroud)

进行设置,delete=True以便在文件关闭后立即将其删除.

现在,在with您的帮助下,您始终可以保证文件将被关闭,从而被删除:

from tempfile import NamedTemporaryFile
from datetime import datetime

# view callable
def export(request):
    response = Response(content_type='application/csv')
    with NamedTemporaryFile(prefix='XML_Export_%s' % datetime.now(),
                            suffix='.xml', delete=True) as f:
        # this is where I usually put stuff in the file
        response.app_iter = f
        response.headers['Content-Disposition'] = ("attachment; filename=Export.xml")
        return response
Run Code Online (Sandbox Code Playgroud)