将文件流式传输到Pylons中的HTTP响应

时间:2010-03-10 00:35:20

标签: python http pylons

我有一个Pylons控制器操作需要将文件返回给客户端。 (该文件位于Web根目录之外,因此我不能直接链接到它。)最简单的方法当然是:

    with open(filepath, 'rb') as f:
        response.write(f.read())

这样可行,但对于大文件来说效率显然不高。最好的方法是什么?我无法在Pylons中找到任何方便的方法来流式传输文件的内容。我是否真的必须从头开始编写代码来一次读取一个块?

3 个答案:

答案 0 :(得分:8)

使用的正确工具是shutil.copyfileobj,它一次从一个块复制到另一个块。

使用示例:

import shutil
with open(filepath, 'r') as f:
    shutil.copyfileobj(f, response)

这不会导致非常大的内存使用量,也不需要自己实现代码。

应该采取常规的异常处理 - 如果处理信号(例如SIGCHLD),则必须处理EINTR,因为对响应的写入可能会中断,并且在执行I / O时可能由于各种原因而发生IOError / OSError。

答案 1 :(得分:5)

由于 Chris AtLee THC4k (来自this answer),我终于使用FileApp课程开始工作了。此方法还允许我设置Content-Length标头something Pylons has a lot of trouble with,这使浏览器能够显示剩余时间的估计值。

这是完整的代码:

def _send_file_response(self, filepath):
    user_filename = '_'.join(filepath.split('/')[-2:])
    file_size = os.path.getsize(filepath)

    headers = [('Content-Disposition', 'attachment; filename=\"' + user_filename + '\"'),
               ('Content-Type', 'text/plain'),
               ('Content-Length', str(file_size))]

    from paste.fileapp import FileApp
    fapp = FileApp(filepath, headers=headers)

    return fapp(request.environ, self.start_response)

答案 2 :(得分:1)

这里的关键是WSGI和扩展的pylons使用可迭代的响应。所以你应该能够编写一些代码(如下面的警告,未经测试的代码!):

def file_streamer():
    with open(filepath, 'rb') as f:
        while True:
            block = f.read(4096)
            if not block:
                break
            yield block
response.app_iter = file_streamer()

此外,paste.fileapp.FileApp旨在为您返回文件数据,因此您也可以尝试:

return FileApp(filepath)

在控制器方法中。