2012-11-12 15 views
10

Şu anda birkaç geçici dosyanın istekleri sırasında işlem yaptığı bir sunucu tarafı json arabirimi geliştiriyorum.Send_file ile kullanılan geçici dosya nasıl temizlenir?

isteği sonunda bu dosyaları temizlemek için geçerli benim çözüm şöyle görünür:

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

, temizleme nesnesindeki dantel alır .__ çıkış __() bir Ancak

kodu şöyle ki bu durumda ben müşteriye bir geçici dosyaları dönmek gerekiyor birkaç vakada,:

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

Bu, şu anda çalışmıyor, ben temizleme Plac alır çünkü e şişesi, dosyayı okuma ve istemciye gönderme işlemidir. ¨ Bunu nasıl çözebilirim?

Düzenleme: Dosyaları geçici dizinlerde bulunduğundan bahsetmeyi unuttum.

cevap

6

Eğer Flask 0.9 veya üzeri Eğer after_this_request dekoratör kullanabilirsiniz kullanıyorsanız:

@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) 

DÜZENLEME o yana

çalışmaz, (bu varsayar yerine cStringIO kullanarak deneyebilirsiniz dosyalarınız belleğe sığacak kadar küçüktür):

Alternatif olarak, c Geçici dosyaları şimdi yaptığınız gibi yineleyin, ancak değil uygulamanızı silmek için uygulamanıza bağlıdır. Bunun yerine, her saat çalışacak şekilde bir cron işi (veya Windows üzerinde çalışıyorsanız Zamanlanmış Görev) kurun ve yarım saatten daha önce oluşturulmuş geçici dizininizdeki dosyaları silin.

+0

İyi görünüyor, ve evet, ben flask kullanıyorum 0.9 :) – monoceres

+0

Cevabım bunun yanında kirli bir hack gibi hissediyor. – madjar

+0

Maalesef, flask hala dosyada @after_this_request'in çağrıldığı dosyaya sahip görünüyor :( – monoceres

3

İki çözümüm var.


ilk çözüm __exit__ yöntemde dosyayı silmek, ama bunu kapatmak getirmemektir. Bu şekilde, dosya nesnesi hala erişilebilir ve send_file'a iletebilirsiniz.

Bu, yalnızca dosya adını kullandığı için kullanmıyorsanız çalışır.


İkinci çözüm çöp toplayıcısına güvenmektir. Silme işlemi (__del__ yöntemi) temizlenecek olan bir dosya nesnesine send_file geçirebilirsiniz. Bu şekilde, dosya sadece dosya nesnesi python'dan silindiğinde silinir. Henüz yoksa, TemporaryFile'u kullanabilirsiniz.

+0

İlginç, bunları gözden geçireceğim seçenekler, ayrıca dizinler ile ilgili benim düzenleme görüyorum – monoceres

+0

İlk çözüm hala çalışır, çünkü (linux en azından) açılan dosya hala dosya kaldırıldıktan sonra (bağlanmamış) okunabilir gerçeğine dayanmaktadır. temizlemeyi yapan nesne dosya nesnesiyse – madjar

2

Biraz geç oldu, ancak bu, madjar's önerilerini kullanarak yaptığım şeydir (başka biri bununla karşılaşırsa). Bu, kullandığınız küçük bir yardımcı işlevdir (durumunuza uyarlayabileceğiniz bir PyExcelerate Workbook nesnesini parametre olarak alır). Sadece tempfile.TemporaryFile'ınızı yarattığınız/oluşturduğunuz şekli değiştirin ve siz ayarlayın! Windows 8.1 ve Ubuntu 12.04 üzerinde test edilmiştir.

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

ben kullandım yöntem yanıtı tamamlandıktan sonra dosyayı silmek zayıf başvurular kullanmaktır.

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() 

Ve ben şişe çağrısında

:

@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 

Bu oldukça geneldir ve bir yaklaşım üç farklı piton web çerçeveler arasında çalıştı gibi ben kullandım söyledi.

+0

Bu çözüm yardımcı oldu.Kodum tarafından üç dosyanın oluşturulduğu bir durum var.Bir kullanıcı bir dosya indirmeyi seçerse, diğerleri silinir. ama sanırım bir Windows ortamında olduğum için bunun için teşekkürler. – mattrweaver