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

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


咨詢
建站咨詢
