2012-11-12 32 views
10

我目前正在開發一個服務器端json接口,其中有幾個臨時文件在請求期間處理。如何清理與send_file一起使用的臨時文件?

我的用於在請求結束清理這些文件當前解決方案是這樣的:

@app.route("/method",methods=['POST']) 
def api_entry(): 
    with ObjectThatCreatesTemporaryFiles() as object: 
     object.createTemporaryFiles() 
     return "blabalbal" 

在這種情況下,清理需要花邊在對象.__出口__()

然而,在少數情況下,我需要到一個臨時文件返回給客戶端,在這種情況下,代碼如下所示:

@app.route("/method",methods=['POST']) 
def api_entry(): 
    with ObjectThatCreatesTemporaryFiles() as object: 
     object.createTemporaryFiles() 
     return send_file(object.somePath) 

目前這是不行的,因爲當我清理需要PLAC燒瓶正在讀取文件並將其發送到客戶端。 ¨ 我該如何解決這個問題?

編輯:我忘了提及這些文件位於臨時目錄。

回答

6

如果您使用的瓶0.9或更高版本可以使用after_this_request裝飾:

@app.route("/method",methods=['POST']) 
def api_entry(): 
    tempcreator = ObjectThatCreatesTemporaryFiles(): 
    tempcreator.createTemporaryFiles() 

    @after_this_request 
    def cleanup(response): 
     tempcreator.__exit__() 
     return response 

    return send_file(tempcreator.somePath) 

編輯

由於不工作,你可以嘗試使用cStringIO代替(這裏假設你的文件足夠小以適應內存):

@app.route("/method", methods=["POST"]) 
def api_entry(): 
    file_data = dataObject.createFileData() 
    # Simplest `createFileData` method: 
    # return cStringIO.StringIO("some\ndata") 
    return send_file(file_data, 
         as_attachment=True, 
         mimetype="text/plain", 
         attachment_filename="somefile.txt") 

或者,你可以c按照現在的方式重新創建臨時文件,但而不是取決於您的應用程序以刪除它們。相反,設置一個cron作業(如果您在Windows上運行,則爲Scheduled Task),每隔一小時左右運行一次,並刪除臨時目錄中超過半小時前創建的文件。

+0

看起來不錯,是的,我正在使用燒瓶0.9 :) – monoceres

+0

我的答案感覺就像這個旁邊的骯髒的黑客。 – madjar

+0

不幸的是,在@after_this_request被調用的時候,燒瓶仍然打開文件:( – monoceres

3

我有兩個解決方案。


第一個解決方法是刪除__exit__方法的文件,但不能關閉它。這樣,文件對象仍然可以訪問,您可以將它傳遞給send_file

這隻會工作,如果你不使用,因爲它使用的文件名。


第二個解決方案是依靠垃圾收集器。您可以傳遞給send_file一個文件對象,該文件對象將在刪除時清除文件(__del__方法)。這樣,只有在從python刪除文件對象時纔會刪除該文件。如果你還沒有,可以使用TemporaryFile

+0

有趣的是,我會檢查這些選項,另請參閱我的編輯有關的目錄 – monoceres

+0

第一個解決方案仍然有效,因爲它是基於(至少在linux上)打開的文件仍然可以在文件被刪除(取消鏈接)後讀取的事實。如果執行清理的對象是文件對象 – madjar

2

這是一個有點晚了,但是這是我做過什麼用madjar's建議(如果任何人遇到這一點)。這是我使用的一個小幫助函數(它使用一個PyExcelerate Workbook對象作爲參數),它可以適應您的情況。只要改變你創建/建立你的tempfile.TemporaryFile的方式,你就設置好了!在Windows 8.1和Ubuntu 12.04上測試。

def xlsx_to_response(wb, filename): 
    f = tempfile.TemporaryFile() 
    wb._save(f) 
    f.seek(0) 
    response = send_file(f, as_attachment=True, attachment_filename=filename, 
         add_etags=False) 

    f.seek(0, os.SEEK_END) 
    size = f.tell() 
    f.seek(0) 
    response.headers.extend({ 
     'Content-Length': size, 
     'Cache-Control': 'no-cache' 
    }) 
    return response 
3

我使用的方法是在響應完成後使用弱引用來刪除文件。

import shutil 
import tempfile 
import weakref 

class FileRemover(object): 
    def __init__(self): 
     self.weak_references = dict() # weak_ref -> filepath to remove 

    def cleanup_once_done(self, response, filepath): 
     wr = weakref.ref(response, self._do_cleanup) 
     self.weak_references[wr] = filepath 

    def _do_cleanup(self, wr): 
     filepath = self.weak_references[wr] 
     print('Deleting %s' % filepath) 
     shutil.rmtree(filepath, ignore_errors=True) 

file_remover = FileRemover() 

和燒瓶呼叫我:

@app.route('/method') 
def get_some_data_as_a_file(): 
    tempdir = tempfile.mkdtemp() 
    filepath = make_the_data(dir_to_put_file_in=tempdir) 
    resp = send_file(filepath) 
    file_remover.cleanup_once_done(resp, tempdir) 
    return resp 

這是相當普遍的,並作爲一種方法已在三個不同的Python Web框架的工作,我已經使用。

+0

這個解決方案很有幫助我有一種情況,我的代碼創建了三個文件,如果用戶選擇下載一個文件,其他文件將被刪除。 ,但我認爲這是因爲我在Windows環境中,感謝這一點。 – mattrweaver

相關問題