2010-03-10 109 views
6

我有一個Pylons控制器操作,需要將文件返回給客戶端。 (該文件是網站根目錄外,這樣我就可以不只是直接鏈接到它。)最簡單的方法是,當然,這樣的:將文件流式傳輸到Pylons中的HTTP響應中

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

這樣的作品,但它是大文件顯然效率不高。什麼是最好的方法來做到這一點?我一直無法在Pylons中找到任何方便的方法來傳輸文件的內容。我是否真的必須編寫代碼才能從頭開始一次讀取塊?

+2

對於提供文件服務,請務必在'rb'方式打開它們,這樣你就不會獲得一個Windows服務器上運行的錯位的結果。 – bobince 2010-03-10 17:06:33

+0

好點,bobince - 將它改爲'rb' – EMP 2010-03-10 23:08:45

回答

5

我終於得到它使用FileApp類,由於工作克里斯·阿特利THC4k(從this answer)。此方法還允許我設置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) 
7

要使用的正確工具是shutil.copyfileobj,它一次從一個塊複製到另一個塊。

用法示例:

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

這不會導致非常大的內存使用情況,並且不需要執行自己的代碼。

應該採取常規的異常處理措施 - 如果您處理信號(如SIGCHLD),則必須處理EINTR,因爲寫入響應可能會中斷,並且IOError/OSError在執行I/O操作時可能出於各種原因。

+0

這正是我所期待的 - 謝謝! – EMP 2010-03-10 05:59:28

+0

嗯,它似乎工作,但我最近用2GB的文件試了一下,發現它仍然需要很長時間才能返回任何內容,並且該進程的內存使用率達到了2.5GB。所以看來,Pylons響應仍然緩衝整個文件。 – EMP 2010-05-06 01:25:59

1

這裏的關鍵是,WSGI和擴展的掛架可以用於可迭代的響應。所以,你應該能夠寫這樣一些代碼(警告,下面未經測試的代碼!):

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) 

在您的控制器方法中。

+0

對不起,這沒有幫助。 'file_streamer'方法返回數據,但它仍然被緩衝。當我嘗試返回'FileApp(filepath)'我得到'TypeError:'FileApp'對象是不可迭代的「 – EMP 2010-05-06 05:06:35

+0

啊,看起來它只是需要多一點的代碼,但基本上'FileApp'做我想做的。我將單獨發佈完整答案。謝謝! +1 – EMP 2010-05-06 06:40:55

+0

向前返回(FileApp(filepath)) – 2010-07-07 22:18:57

相關問題