tornado上传大文件以及多文件上传
tornado上传大文件问题解决方法
tornado默认上传限制为低于100M,但是由于需要上传大文件需求,网上很多说是用nginx,但我懒,同时不想在搞一个服务了。
解决方法:
server = HTTPServer(application, max_buffer_size=504857600, max_body_size=504857600) server.bind(options.port) server.start(5) # Forks multiple sub-process tornado.ioloop.IOLoop.current().start()
具体再去看源码,stackoverflow和/segmentfault.com给了我提示,然后跑去看了眼源码
TCPserver
.....
From上传文件
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): file_metas = self.request.files["fff"] # print(file_metas) for meta in file_metas: file_name = meta['filename'] import os file_name = os.path.join("img", file_name) with open(file_name,'wb') as up: up.write(meta['body']) settings = { 'template_path': 'template', } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>上传文件</title> </head> <body> <!--表单中enctype="multipart/form-data"的意思,是设置表单的MIME编码。--> <!--默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;--> <!--只有使用了multipart/form-data,才能完整的传递文件数据,进行下面的操作. --> <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" > <input name="fff" id="my_file" type="file" /> <input type="submit" value="提交" /> </form> </body> </html>
AJAX上传
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" /> <script> function UploadFile(){ var fileObj = document.getElementById("img").files[0]; var form = new FormData(); form.append("k1", "v1"); form.append("fff", fileObj); var xhr = new XMLHttpRequest(); xhr.open("post", '/index', true); xhr.send(form); } </script> </body> </html>
dataType:"json", -----主意加上这句
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" /> <script src="/static/jquery-1.12.4.js"></script> <!--<script src="{{static_url('jquery-1.9.1.min.js')}}"></script> 也可以这么写--> <script> function UploadFile(){ var fileObj = $("#img")[0].files[0]; var form = new FormData();//创建一个form对象类似<form> form.append("k1", "v1"); form.append("fff", fileObj); $.ajax({ type:'POST', url: '/index', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType //如果不写这两句,改变里面的格式,影响内容 success: function(arg){ console.log(arg); } }) } </script> </body> </html>
思考一个问题:
如果我要是有两个上传的框呢?怎么办
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src="/static/admin/js/jquery-1.10.2.js"></script> </head> <body> <input type="file" id="img1"/> <input type="file" id="img2"/> <input type="button" onclick="UploadFile();" value="上传"/> <script type="text/javascript"> function UploadFile(){ var fileObj1 = $("#img1")[0].files[0]; var fileObj2 = $("#img2")[0].files[0]; var form = new FormData();//创建一个form对象类似<form> form.append("k1", "v1"); form.append("file1", fileObj1); form.append("file2", fileObj2); $.ajax({ type:'POST', url: '/TestUploadFile', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType //如果不写这两句,改变里面的格式,影响内容 success: function(arg){ console.log(arg); } }) } </script> </body> </html>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" > <div id="main"> <input name="fff" id="my_file" type="file" /> <input type="button" name="action" value="Upload" onclick="redirect()"/> <iframe id='my_iframe' name='my_iframe' src="" class="hide"></iframe> </div> </form> <script> function redirect(){ document.getElementById('my_iframe').onload = Testt; document.getElementById('my_form').target = 'my_iframe'; document.getElementById('my_form').submit(); } function Testt(ths){ var t = $("#my_iframe").contents().find("body").text(); console.log(t); } </script> </body> </html>
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): file_metas = self.request.files["fff"] # print(file_metas) for meta in file_metas: file_name = meta['filename'] with open(file_name,'wb') as up: up.write(meta['body']) settings = { 'template_path': 'template', } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
补充:如果python后台想得到aaa的值,需要用self.argument('aaa'),免得自己忘记了。感谢二卷!
'static_path': 'static',
<script type="text/javascript"> $(document).ready(function () { $("#formsubmit").click(function () { var iframe = $('<iframe name="postiframe" id="postiframe" style="display: none"></iframe>'); $("body").append(iframe); var form = $('#theuploadform'); form.attr("action", "/upload.aspx"); form.attr("method", "post"); form.attr("encoding", "multipart/form-data"); form.attr("enctype", "multipart/form-data"); form.attr("target", "postiframe"); form.attr("file", $('#userfile').val()); form.submit(); $("#postiframe").load(function () { iframeContents = this.contentWindow.document.body.innerHTML; $("#textarea").html(iframeContents); }); return false; }); }); </script> <form id="theuploadform"> <input id="userfile" name="userfile" size="50" type="file" /> <input id="formsubmit" type="submit" value="Send File" /> </form> <div id="textarea"> </div>
tornado多文件上传js代码
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="file" multiple="multiple"/> <input type="button" value="提交" onclick="UploadFile();" /> <script src="/static/jquery-1.12.4.js"></script> <script> function UploadFile(){ var fileObj = $("#file")[0].files; var form = new FormData();//创建一个form对象类似<form> for(var i=0;i<fileObj.length;i++){ form.append("file", fileObj[i]); } // var fileObj1 = $("#file")[0].files[1]; // var form = new FormData();//创建一个form对象类似<form> // form.append("file", fileObj); // form.append("file", fileObj1); $.ajax({ type:'POST', url: '/index', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType //如果不写这两句,改变里面的格式,影响内容 success: function(arg){ console.log(arg); } }) } </script> </body> </html>
下载 ===注意: 中文名字会出现错误,需要重命名
# @authenticated # def get(self): # print("2222222222222") # locale = self.get_cookie("user_locale","zh_CN") # msg = lang_upgrade[locale] # back_filename_path = os.path.join(TEP_PATH,backup_filename) # print('back_filename_path = ',back_filename_path) # if os.path.exists(back_filename_path) and os.path.isfile(back_filename_path): # self.set_header("Content-Type", "application/x-zip-compressed") # self.set_header("Content-Disposition", "attachment; filename=%s" % backup_filename) # f = open(back_filename_path,'rb') # while True: # b = f.read(8096) # if not b: # break # else: # self.write(b) # self.flush() # f.close() # else: # self.write(msg[4010])
前端对应代码:
window.location.href=DownFileAPI + "?UserID=" + userId + "&&TokenID=" + encodeURIComponent(tokenId) + "&&FilePathName=" + encodeURIComponent(dataVa)
下载报错信息:latin-1 codec cant encode characters in position 42-48: ordinal not in range256
今天遇到报错: latin-1 codec cant encode characters in position 42-48: ordinal not in range256
原因: 因为文件名是中文, header无法解析, 所以报错。
那这个时候怎么办呢?
解决办法:
FilePathName = self.get_argument("FilePathName", None) #获取文件名 FileName = str(FilePathName.split("/")[-1]).strip() # 得到文件名 latinFileName = FileName.encode("utf-8").decode("latin1") # 这句很关键, 要解析成latin-1才OK,这样就不会报错
示例:
class DownFileHandler(downBaseRequestHandler): @tornado.gen.coroutine def get(self, *args, **kwargs): if self.verifyFlag == 1 and self.status == 0: status = 2000 try: FilePathName = self.get_argument("FilePathName", None) FilePathName = MyBase64.decryption(unquote(FilePathName)) # 这句是解密 FileName = str(FilePathName.split("/")[-1]).strip() latinFileName = FileName.encode("utf-8").decode("latin1") # 这句很关键, 要解析成latin-1才OK,这样就不会报错 newFileName = str(int(time.time())) + "." + FileName.split(".")[1] # 第二种方式就是换一个文件名 self.set_header("Content-Type", "application/x-zip-compressed") # -----<或者这么写> ----- # # self.set_header("Content-Type", "application/octet-stream") self.set_header("Content-Disposition", "attachment; filename=%s" % latinFileName) f = open(FilePathName, 'rb') while True: b = f.read(8096) if not b: break else: self.write(b) self.flush() f.close() except Exception as e: e = FormatErrorCode(e) my_log.error(e) status = int(e[0]) self.write(json.dumps(result(status=status))) self.finish() else: self.write(json.dumps(result(status=4005))) self.finish()
上传文件写入到文件夹并返回文件信息封装类
import hashlib class UploadFile: ''' USE METHOD: from app import static_path # static_path==filePath--> '/opt/code/...' article_little_img = self.request.files["article_little_img"][0] UploadFile(article_little_img, static_path) ''' def __init__(self, fileobj, static_path): ''' :param fileobj: :param static_path: ''' self.fileobj = fileobj self.static_path = static_path self.md5 = None self.size = None self.saveFile(self.fileobj) def getFullName(self, fileobj): return fileobj['filename'] def getFilePath(self): # 获取文件完整路径 rootPath = self.static_path # app里面总路径 filePath = datetime.datetime.now().strftime("%Y%m%d") # for path in []: # filePath = os.path.join(filePath, path) return os.path.join(rootPath, 'admin', 'upload', 'img', filePath) def saveFile(self, fileobj): self.fullName = self.getFullName(fileobj) self.filePath = self.getFilePath() # 检查路径是否存在,不存在则创建 if not os.path.exists(self.filePath): os.makedirs(self.filePath) self.filePathName = os.path.join(self.filePath, self.fullName) md5_value = hashlib.md5() with open(self.filePathName, 'wb') as fp: fp.write(fileobj['body']) md5_value.update(fileobj['body']) self.md5 = md5_value.hexdigest() self.size = len(fileobj['body']) def getFileInfo(self): ''' :return: ''' # 获取当前上传成功文件的各项信息 ''' # 注意替换 static路径 --> 用总路径替换static_path 得到后面路径,然后. http://192.168.2.137:8888/ + sub_filepathname self.filePathName = '/opt/code/zzz/static/upload/img/123/123.png' static_path = '/opt/code/zzz/' url = http://192.168.2.137:8888/ + sub_filepathname ''' return { 'state': 1, 'url': '', 'title': '', 'type': self.fullName.split('.')[0], 'size': self.size, 'md5': self.md5, 'fileName': self.fullName, 'filePath': self.filePath, 'filePathName': self.filePathName, 'fileDate': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), }
作者:沐禹辰
出处:http://www.cnblogs.com/renfanzi/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
出处:http://www.cnblogs.com/renfanzi/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。