tornado 静态文件,tornado文档
文件上传的服务端技术解析
俗话说,爱有多深,恨就有多深。龙卷风服务器就是这样一个矛盾体,它的缺点和优点一样明显和强烈。有人认为文件上传是tornado的一大缺陷,tornado将用户上传的文件存储在内存3354中,这意味着如果多个用户同时上传文件,内存开销会急剧增加。然而,我认为它使许多事情变得更容易。比如你要处理用户上传的内容,你就不用再打开文件了,因为内容在内存里。此外,在tornado的异步机制下,我不确定多个用户可以同时上传文件。这是一个有趣的问题。
好了,言归正传。假设文件上传形式如下:
formid= form _ upload action=/demo/upload enctype= multipart/form-data method= post
input type= file name= want _ to _ upload _ file _ 1 /br/
input type= file name= want _ to _ upload _ file _ 2 /br/
输入=提交值=上传/
/form机制允许一次上载多个文件。这里有几个问题需要特别说明。
在提交表单之前,您需要为表单指定action和method的属性值。如果是上传文件,还需要设置enctype="multipart/form-data "。这三个属性可以用html写,也可以在提交前由js赋值。
文件浏览是文件类型的输入标签自带的功能,程序员无法在浏览器框架内操作本地文件。标签的name属性用于将它与其他文件区分开,不是文件名,也不是文件对象,也不是文件内容。
上面的表单提交到/demo/upload(假设上传的第一个文件名是dqd.jpg,第二个文件名是intro.png)。请求的对象包含文件字典,所有上传文件的信息都包含在这个结构中。让我们来看看这个请求的真实面目。文件:
defpost(self):
print self . request . files . keys()#[u want _ to _ upload _ file _ 1 ,uwant_to_upload_file_2]
打印类型(self . request . files[ want _ to _ upload _ file _ 1 ])#长度为1的列表
meta _ file _ 1=self . request . files[ want _ to _ upload _ file _ 1 ][0]
printmeta_file_1.keys()#[body , content_type , filename]
Len (meta _ file _ 1 [body]) # 31492,文件长度
print meta _ file _ 1[ content _ type ]# image/JPEG
meta _ file _ 1[ filename ]# dqd.jpg有了这些材料,我们可以尽一切努力来满足客户的需求。比如不做任何处理,直接用原文件名保存在指定路径(假设保存在/static/image/wiki目录下):
lass="brush:php;toolbar:false">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'])
withopen(file_name,'wb')asfp:
fp.write(meta_file_1['body'])很多时候,需要对用户上传的文件重命名(比如,用时间戳为文件名),但文件后缀名不变。
fn,ext=os.path.splitext(meta_file_1['filename'])如果需要对用户上传的文件类型做检查,请使用文件的content_type,而不是文件的扩展名,因为前者更规范。比如,JPEG类型的图片文件,其后缀名可能是.jpg.jpeg.JPG.JPEG中的一种,而前者只有“image/jpeg”一种表示法。fn='%d%s'%(time.time()*1000,ext)
file_name=os.path.join(upload_path,fn)
关于文件的content_type,网上资料多如牛毛,请自行搜索。
处理用户上传的图片文件时,除了限制文件大小,有时候还要做缩放处理,甚至一并生成缩略图,此时就需要将文件内容转成易于处理的图像对象,比如,pil的Image。
fromPILimportImage至于如何缩放、如何保存为文件,请自行检索相关资料。importStringIO
pilImg=Image.open(StringIO.StringIO(meta_file_1['body']))
printpilImg.size
基于Ajax技术实现的文件上传客户端
假定上传文件的表单是这样的:
<formid="form_upload"action="/demo/upload"enctype="multipart/form-data"method="post">方法1:使用 ajaxfileupload.js<inputtype="file"name="wiki_img"id="wiki_img"/><br/>
<inputid="doUpload"type="button"value="上传"/>
</form>
<scriptsrc="jquery.js"></script>方法2:仅依赖 jquery.js<scriptsrc="ajaxfileupload.js"></script>
<scripttype="text/javascript">
$("#doUpload").click(function(){
$.ajaxFileUpload({
url:'/demo/upload',
secureuri:false,
fileElementId:'wiki_img',
dataType:'json',
success:function(data){
alert(data);
}
});
});
</script>
<scriptsrc="jquery.js"></script>文件下载的服务端技术解析<scripttype="text/javascript">
varformData=newFormData();
formData.append("file",$("#wiki_img")[0].files[0]);
formData.append("filename",$("#wiki_img").val());
$.ajax({
url:'/demo/upload',
type:'POST',
async:false,
data:formData,
processData:false,
contentType:false,
beforeSend:function(){
$("#upload_tips").html("正在进行,请稍候");
},
success:function(data){
alert(data);
}
});
</script>
相对于上传,文件的下载就简单得多。只需要记住两点:开始前告诉浏览器要传输的文件类型,结束前对浏览器说拜拜。文件类型并不是固定的,需要根据文件的实际情况来选择。详情请自行检索。
defget(self):配合seek命令,可以实现更复杂的下载请求,比如,断点续传、分块下载、ajax异步请求等。self.set_header('Content-Type','application/octet-stream')
withopen(filename,'rb')asf:
whileTrue:
data=f.read(buf_size)
ifnotdata:
break
self.write(data)
self.finish()
众多python培训视频,尽在盛行IT软件开发工作室,欢迎在线学习!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。