tornado:如何创建一个写入RequestHandler的类文件对象?

1 投票
1 回答
748 浏览
提问于 2025-04-18 14:45

在我的应用程序中,我想创建一个处理程序,用来将大文件传输给客户端。这些文件是由另一个模块生成的(具体来说是用tarfile)。

我想要的是一个类似文件的对象,它不是写入到网络连接或者硬盘上的实际文件,而是转发到RequestHandler.write方法。

这是我目前简单实现的样子:

import tornado.gen
import tornado.ioloop
import tornado.web


class HandlerFileObject(object):
    def __init__(self, handler):
        self.handler = handler

    @tornado.gen.coroutine
    def write(self, data):
        self.handler.write(data)
        yield self.handler.flush()

    def close(self):
        self.handler.finish()


class DownloadHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_status(200)
        self.set_header("Content-Type", "application/octet-stream")
        fp = HandlerFileObject(self)
        with open('/dev/zero', 'rb') as devzero:
            for _ in range(100*1024):
                fp.write(devzero.read(1024))
        fp.close()


if __name__ == '__main__':
    app = tornado.web.Application([
        (r"/", DownloadHandler)
    ])
    app.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

这个方法可以工作,但问题是所有的数据都被加载到内存中,并且在我停止应用程序之前不会释放。有没有更好、更合适的方法来处理这个问题呢?

1 个回答

3

get() 这个函数也需要是一个协程,并且在调用 fp.write() 时需要暂停一下。把写入操作变成协程后,你的对象就不那么像一个文件了——大多数调用这个函数的人会忽略它的返回值,这样就可能隐藏了错误,并且影响了程序的控制流程。文件的操作通常是同步的,所以你可能需要在其他线程中进行这些操作,这样你就可以根据需要让它们暂停。

撰写回答