python - HTTP 下载非常大的文件

标签 python http download twisted

我正在使用 Python/Twisted 开发 Web 应用程序。

我希望用户能够下载一个非常大的文件(> 100 Mb)。当然,我不想将所有文件加载到(服务器的)内存中。

服务器端我有这样的想法:

...
request.setHeader('Content-Type', 'text/plain')
fp = open(fileName, 'rb')
try:
    r = None
    while r != '':
        r = fp.read(1024)
        request.write(r)
finally:
    fp.close()
    request.finish()

我希望这能奏效,但我遇到了问题: 我正在用 FF 进行测试...浏览器似乎让我等到文件下载完成,然后我有打开/保存对话框。

我希望立即出现对话框,然后是正在运行的进度条...

也许我必须在 Http header 中添加一些内容...比如文件的大小?

最佳答案

您发布的示例代码的两个大问题是它是非合作的,它在发送之前将整个文件加载到内存中。

while r != '':
    r = fp.read(1024)
    request.write(r)

请记住,Twisted 使用协作式多任务处理来实现任何类型的并发。所以这个片段的第一个问题是它是一个 while 循环遍历整个文件的内容(你说它很大)。这意味着整个文件将被读入内存并写入响应,然后再任何过程中可能发生的其他事情。在这种情况下,碰巧“anything”还包括将字节从内存缓冲区推送到网络上,因此您的代码也会立即将整个文件保存在内存中,并且只开始获取当此循环完成时将其删除。

因此,作为一般规则,您不应编写用于基于 Twisted 的应用程序的代码,该应用程序使用像这样的循环来完成大工作。相反,您需要以与事件循环合作的方式完成大工作的每一小部分。要通过网络发送文件,最好的方法是使用生产者消费者。这是两个相关的 API,用于使用缓冲区空事件高效地移动大量数据,而不会浪费不合理的内存量。

您可以在此处找到这些 API 的一些文档:

http://twistedmatrix.com/projects/core/documentation/howto/producers.html

幸运的是,对于这种非常常见的情况,还有一个已经编写好的生产者可供您使用,而不是实现您自己的生产者:

http://twistedmatrix.com/documents/current/api/twisted.protocols.basic.FileSender.html

你可能想像这样使用它:

from twisted.protocols.basic import FileSender
from twisted.python.log import err
from twisted.web.server import NOT_DONE_YET

class Something(Resource):
    ...

    def render_GET(self, request):
        request.setHeader('Content-Type', 'text/plain')
        fp = open(fileName, 'rb')
        d = FileSender().beginFileTransfer(fp, request)
        def cbFinished(ignored):
            fp.close()
            request.finish()
        d.addErrback(err).addCallback(cbFinished)
        return NOT_DONE_YET

您可以在我的博客 http://jcalderone.livejournal.com/50562.html 上阅读有关 NOT_DONE_YET 和其他相关想法的“60 秒扭曲 Web”系列的更多信息(具体参见“异步响应”条目)。

关于python - HTTP 下载非常大的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1538617/

相关文章:

python - Pandas 非连续数字过滤器丢弃 0 行

python - matplotlib mathtext\frac 太小

rest - HTTP 方法 - POST 与 PATCH 或 PUT - 当用户实际上不打算更新任何内容时

Java Servlet 下载

javascript - 下载属性的 Electron 问题

python - Django 中的 TypedChoiceField 或 ChoiceField

python - 如何交付随时可用的软件?

Python asyncio.gather 返回 None

c++ - Http post - 发送大数据时连接重置 vc++

c# - Response.WriteFile 两次写入内容