新聞中心
文件上傳的服務(wù)端技術(shù)解析

常言到,愛有多深、恨有多切。tornado服務(wù)器就是這樣一個矛盾體,它的缺點和它的優(yōu)點一樣,顯著且強烈。有人認(rèn)為,文件上傳是tornado的重大缺陷之一,它把用戶上傳的文件存放在內(nèi)存中——這意味著多用戶同時上傳文件的話,內(nèi)存的開銷會急劇增加。不過我倒是覺得,這反倒讓很多事情變得簡單了,比如,你想對用戶上傳的內(nèi)容做處理的話,不用再打開文件了,因為內(nèi)容就在內(nèi)存中。再者說,在tornado的異步機制下,我不確定真的能夠多用戶同時上傳文件。這是一個有趣的問題。
好了,言歸正傳吧。假定文件上傳的表單如下:
機制是允許一次上傳多個文件的。這里有幾個問題需要特別說明一下。
在提交表單之前,需要為form指定action和method的屬性值,如果是上傳文件,還要設(shè)置enctype=“multipart/form-data”。這三個屬性,可以寫在html中,也可以在submit之前用js的方法為其賦值。
文件瀏覽是file類型的input標(biāo)簽自備的功能,程序員無法在瀏覽器框架內(nèi)操作本地文件。該標(biāo)簽的name屬性,是用來區(qū)別于其他文件的標(biāo)識,不是文件名,也不是文件對象,更不是文件內(nèi)容。
上面的表單被提交到/demo/upload(假定上傳的第1個文件名為dqd.jpg,第2個文件名為intro.png),這個請求的對象中包含files字典,上傳的全部文件的信息都包含在這個結(jié)構(gòu)中。我們來看看這個request.files的真實面貌:
def post(self): print self.request.files.keys() # [u'want_to_upload_file_1', u'want_to_upload_file_2'] print type(self.request.files['want_to_upload_file_1']) # list,長度為1 meta_file_1 = self.request.files['want_to_upload_file_1'][0] print meta_file_1.keys() # ['body', 'content_type', 'filename'] print len(meta_file_1['body']) # 31492,文件長度 print meta_file_1['content_type'] # image/jpeg print meta_file_1['filename'] # dqd.jpg
有了這些素材,我們就可以無所不能地應(yīng)對客戶需求了。比如,不做任何處理,僅僅用原文件名保存在指定路徑下(假設(shè)保存在/static/image/wiki目錄下):
PROJECT_PATH = os.path.split(os.path.realpath(__file__))[0] upload_path = os.path.join(PROJECT_PATH, 'static', 'image', 'wiki') file_name = os.path.join(upload_path, meta_file_1['filename']) with open(file_name, 'wb') as fp: fp.write(meta_file_1['body'])
很多時候,需要對用戶上傳的文件重命名(比如,用時間戳為文件名),但文件后綴名不變。
fn, ext = os.path.splitext(meta_file_1['filename']) fn = '%d%s' % (time.time()*1000, ext) file_name = os.path.join(upload_path, fn)
如果需要對用戶上傳的文件類型做檢查,請使用文件的content_type,而不是文件的擴展名,因為前者更規(guī)范。比如,JPEG類型的圖片文件,其后綴名可能是.jpg|.jpeg|.JPG|.JPEG中的一種,而前者只有“image/jpeg”一種表示法。
關(guān)于文件的content_type,網(wǎng)上資料多如牛毛,請自行搜索。
處理用戶上傳的圖片文件時,除了限制文件大小,有時候還要做縮放處理,甚至一并生成縮略圖,此時就需要將文件內(nèi)容轉(zhuǎn)成易于處理的圖像對象,比如,pil的Image。
from PIL import Image import StringIO pilImg = Image.open(StringIO.StringIO(meta_file_1['body'])) print pilImg.size
至于如何縮放、如何保存為文件,請自行檢索相關(guān)資料。
基于Ajax技術(shù)實現(xiàn)的文件上傳客戶端
假定上傳文件的表單是這樣的:
方法1:使用 ajaxfileupload.js
方法2:僅依賴 jquery.js
文件下載的服務(wù)端技術(shù)解析
相對于上傳,文件的下載就簡單得多。只需要記住兩點:開始前告訴瀏覽器要傳輸?shù)奈募愋停Y(jié)束前對瀏覽器說拜拜。文件類型并不是固定的,需要根據(jù)文件的實際情況來選擇。詳情請自行檢索。
def get(self):
self.set_header ('Content-Type', 'application/octet-stream')
with open(filename, 'rb') as f:
while True:
data = f.read(buf_size)
if not data:
break
self.write(data)
self.finish()配合seek命令,可以實現(xiàn)更復(fù)雜的下載請求,比如,斷點續(xù)傳、分塊下載、ajax異步請求等。
眾多python培訓(xùn)視頻,盡在python創(chuàng)新互聯(lián)教程,歡迎在線學(xué)習(xí)!
分享題目:創(chuàng)新互聯(lián)Python教程:基于tornado服務(wù)器實現(xiàn)文件上傳和下載
網(wǎng)頁路徑:http://m.fisionsoft.com.cn/article/dhigedo.html


咨詢
建站咨詢
