上傳文件javascript
1、自定義上傳文件css
1 from flask import Flask,request 2 from datetime import datetime 3 import random 4 app = Flask(__name__) 5 6 @app.route('/upload',methods=['POST']) 7 def upload(): 8 data = request.files.get('pic') 9 # 隨機圖片名稱 10 pic=datetime.now().strftime('%Y%m%d%H%M%S')+str(random.randint(1000,9999))+'.png' 11 with open(pic,'wb') as f: 12 f.write(data.read()) 13 return '' 14 15 if __name__ == '__main__': 16 app.run(debug=True)
<form action='http://127.0.0.1:5000/upload' method='post' enctype="multipart/form-data"> <input type='file' name='pic' /> <input type='submit' value='submit' /> </form>
2、第三方上傳文件 (webuploader)html
1 # server.py 2 # 引入os模塊,1,刪除分片,節約物理空間,2,遍歷上傳的文件 3 import os 4 from flask import Flask, request, Response, render_template,jsonify 5 app = Flask(__name__) 6 app.config.from_object('config') 7 8 # 進入上傳頁面 9 @app.route('/') 10 def index(): 11 return render_template('uploads.html') 12 13 # 檢查上傳分片是否重複,若是重複則不提交,不然提交 14 @app.route('/checkChunk', methods=['POST']) 15 def checkChunk(): 16 chunkSize = request.form.get('chunkSize') # 待上傳文件的大小 17 if chunkSize == '0': 18 return jsonify({'ifExist': True}) # 不要上傳 19 file_name = request.form.get('fileMd5')+ request.form.get('chunk') 20 if file_name not in get_deep_catalog(): 21 return jsonify({'ifExist': False}) 22 return jsonify({'ifExist':True}) 23 24 # 定義一個獲取當前路徑下的全部文件,應該放在公共函數庫中 25 def get_deep_catalog(path='./upload'): 26 result = [] 27 list_catalog = os.listdir(path) 28 for i in list_catalog: 29 if os.path.isdir(i) == True: 30 get_deep_catalog(i) 31 else: 32 result.append(i) 33 return result 34 35 # 將每次上傳的分片合併成一個新文件 36 @app.route('/mergeChunks', methods=['POST']) 37 def mergeChunks(): 38 fileName=request.form.get('fileName') # 上傳的文件名 39 md5=request.form.get('fileMd5') 40 chunk = 0 # 分片序號 41 with open(u'./upload/{}'.format(fileName), 'wb') as target_file: # 建立新文件 42 while True: 43 try: 44 filename = './upload/{}-{}'.format(md5, chunk) 45 source_file = open(filename, 'rb') # 按序打開每一個分片 46 target_file.write(source_file.read()) # 讀取分片內容寫入新文件 47 source_file.close() 48 except Exception as e: 49 break 50 chunk += 1 51 os.remove(filename) # 刪除該分片,節約空間 52 return jsonify({'upload':True,'fileName':fileName}) 53 54 55 # 前端上傳的分片 保存到 指定的目錄下 ./upload 56 @app.route('/upload', methods=['POST']) 57 def upload(): # 接收前端上傳的一個分片 58 md5=request.form.get('fileMd5') 59 chunk_id=request.form.get('chunk',0,type=int) 60 filename = '{}-{}'.format(md5,chunk_id) 61 upload_file = request.files['file'] 62 upload_file.save('./upload/{}'.format(filename)) 63 return jsonify({'upload_part':True}) 64 65 66 # 遍歷 upload下的上傳文件 67 @app.route('/file/list', methods=['GET']) 68 def file_list(): 69 files = os.listdir('./upload/') # 獲取文件目錄 70 return render_template('list.html', files=files) 71 72 # 文件下載 73 @app.route('/file/download/<filename>', methods=['GET']) 74 def file_download(filename): 75 def send_chunk(): # 流式讀取 76 store_path = './upload/%s' % filename 77 with open(store_path, 'rb') as target_file: 78 while True: 79 chunk = target_file.read(20 * 1024 * 1024) 80 if not chunk: 81 break 82 yield chunk 83 # application/octet-stream 是二進制文件的數據流或者字節數組 84 return Response(send_chunk(), content_type='application/octet-stream') 85 86 if __name__ == '__main__': 87 app.run(debug=True)
1 <!-- 2 上傳頁面 uploads.html 3 extensions : 上傳數據類型 例如 mp4 4 mimeTypes : 媒體資源類型,如 .mp4 5 --> 6 <!DOCTYPE html> 7 <html> 8 <head> 9 <meta charset="UTF-8"> 10 <title>webuploader上傳</title> 11 <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/webuploader/0.1.1/webuploader.css"> 12 <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> 13 <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script> 14 <script src="/static/js/webuploader.min.js"></script> 15 <script type="text/javascript" src="/static/js/hashmap.js"></script> 16 <style type="text/css"> 17 #picker { 18 display: inline-block; 19 line-height: 1.428571429; 20 vertical-align: middle; 21 margin: 0 12px 0 0; 22 } 23 </style> 24 </head> 25 <body> 26 <div id="uploader" class="container"> 27 <!--用來存放文件信息--> 28 <div id="thelist" class="row"> 29 <div class="panel panel-primary"> 30 <div class="panel-heading">webuploader文件上傳</div> 31 <table class="table table-striped table-bordered" id="uploadTable"> 32 <thead> 33 <tr> 34 <th>序號</th> 35 <th>文件名稱</th> 36 <th>文件大小</th> 37 <th>上傳狀態</th> 38 <th>上傳進度</th> 39 <th>操做</th> 40 </tr> 41 </thead> 42 <tbody></tbody> 43 </table> 44 <div class="panel-footer"> 45 <div id="picker">選擇文件</div> 46 <button id="btn" class="btn btn-default">開始上傳</button> 47 </div> 48 </div> 49 </div> 50 </div> 51 <script type="text/javascript"> 52 var fileMd5; 53 var fileSuffix; 54 var $list=$("#thelist table>tbody"); 55 var state = 'pending';//初始按鈕狀態 56 var $btn=$("#btn"); 57 var count=0; 58 var map=new HashMap(); 59 //監聽分塊上傳過程當中的三個時間點 60 WebUploader.Uploader.register({ 61 "before-send-file" : "beforeSendFile", 62 "before-send" : "beforeSend", 63 "after-send-file" : "afterSendFile", 64 }, { 65 //時間點1:全部分塊進行上傳以前調用此函數 66 beforeSendFile : function(file) { 67 var deferred = WebUploader.Deferred(); 68 //1、計算文件的惟一標記,用於斷點續傳 69 // (new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024) 70 (new WebUploader.Uploader()).md5File(file, 0, 1024) 71 .progress(function(percentage) { 72 $('#' + file.id).find("td.state").text("正在讀取文件信息..."); 73 }).then(function(val) { 74 fileMd5 = val; 75 $('#' + file.id).find("td.state").text("成功獲取文件信息..."); 76 //獲取文件信息後進入下一步 77 deferred.resolve(); 78 }); 79 return deferred.promise(); 80 }, 81 //時間點2:若是有分塊上傳,則每一個分塊上傳以前調用此函數 82 beforeSend : function(block) { 83 var deferred = WebUploader.Deferred(); 84 85 $.ajax({ 86 type : "POST", 87 url : "{% raw %}{{url_for('.checkChunk')}}{% endraw %}", 88 data : { 89 //文件惟一標記 90 fileMd5 : fileMd5, 91 //當前分塊下標 92 chunk : block.chunk, 93 //當前分塊大小 94 chunkSize : block.end - block.start 95 }, 96 dataType : "json", 97 success : function(response) { 98 if (response.ifExist) { 99 //分塊存在,跳過 100 deferred.reject(); 101 } else { 102 //分塊不存在或不完整,從新發送該分塊內容 103 deferred.resolve(); 104 } 105 } 106 }); 107 108 this.owner.options.formData.fileMd5 = fileMd5; 109 deferred.resolve(); 110 return deferred.promise(); 111 }, 112 //時間點3:全部分塊上傳成功後調用此函數 113 afterSendFile : function() { 114 //若是分塊上傳成功,則通知後臺合併分塊 115 $.ajax({ 116 type : "POST", 117 url : "{% raw %}{{url_for('.mergeChunks')}}{% endraw %}", 118 data : { 119 fileMd5 : fileMd5, 120 fileSuffix:fileSuffix, 121 fileName:fileName, 122 }, 123 success : function(response) { 124 console.log(response.fileName+" 上傳成功") 125 // alert("上傳成功"); 126 } 127 }); 128 } 129 }); 130 131 var uploader = WebUploader 132 .create({ 133 // swf文件路徑 134 swf : 'https://cdnjs.cloudflare.com/ajax/libs/webuploader/0.1.1/Uploader.swf', 135 // 文件接收服務端。 136 server : '{% raw %}{{ url_for("upload") }}{% endraw %}', 137 // 選擇文件的按鈕。可選。 138 // 內部根據當前運行是建立,多是input元素,也多是flash. 139 pick : { 140 id : '#picker',//這個id是你要點擊上傳文件的id 141 multiple : true 142 }, 143 // 不壓縮image, 默認若是是jpeg,文件上傳前會壓縮一把再上傳! 144 resize : true, 145 auto : false, 146 //開啓分片上傳 147 chunked : true, 148 chunkSize : 10 * 1024 * 1024, 149 150 accept : { 151 extensions : "txt,jpg,jpeg,bmp,png,zip,rar,war,pdf,cebx,doc,docx,ppt,pptx,xls,xlsx,iso,flv,mp4", 152 mimeTypes : '.txt,.jpg,.jpeg,.bmp,.png,.zip,.rar,.war,.pdf,.cebx,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.iso,.flv,.mp4' 153 } 154 155 }); 156 157 // 當有文件被添加進隊列的時候 158 uploader.on('fileQueued', function(file) { 159 //保存文件擴展名 160 fileSuffix=file.ext; 161 fileName=file.source['name']; 162 var fileSize=file.size; 163 var fileSizeStr=""; 164 fileSizeStr=WebUploader.Base.formatSize(fileSize); 165 count++; 166 $list.append( 167 '<tr id="' + file.id + '" class="item" flag=0>'+ 168 '<td class="index">' + count + '</td>'+ 169 '<td class="info">' + file.name + '</td>'+ 170 '<td class="size">' + fileSizeStr + '</td>'+ 171 '<td class="state">等待上傳...</td>'+ 172 '<td class="percentage"></td>'+ 173 '<td class="operate"><button name="upload" class="btn btn-warning">開始</button><button name="delete" class="btn btn-error">刪除</button></td></tr>'); 174 map.put(file.id+"",file); 175 }); 176 177 // 文件上傳過程當中建立進度條實時顯示。 178 uploader.on('uploadProgress', function(file, percentage) { 179 $('#' + file.id).find('td.percentage').text( 180 '上傳中 ' + Math.round(percentage * 100) + '%'); 181 }); 182 183 uploader.on('uploadSuccess', function(file) { 184 $('#' + file.id).find('td.state').text('已上傳'); 185 }); 186 187 uploader.on('uploadError', function(file) { 188 $('#' + file.id).find('td.state').text('上傳出錯'); 189 }); 190 191 uploader.on('uploadComplete', function(file) { 192 uploader.removeFile(file); 193 }); 194 195 196 uploader.on('all', function(type) { 197 if (type === 'startUpload') { 198 state = 'uploading'; 199 } else if (type === 'stopUpload') { 200 state = 'paused'; 201 } else if (type === 'uploadFinished') { 202 state = 'done'; 203 } 204 205 if (state === 'uploading') { 206 $btn.text('暫停上傳'); 207 } else { 208 $btn.text('開始上傳'); 209 } 210 }); 211 212 $btn.on('click', function(){ 213 if (state === 'uploading'){ 214 uploader.stop(true); 215 } else { 216 uploader.upload(); 217 } 218 }); 219 220 $("body").on("click","#uploadTable button[name='upload']",function(){ 221 flag=$(this).parents("tr.item").attr("flag")^1; 222 $(this).parents("tr.item").attr("flag",flag); 223 var id=$(this).parents("tr.item").attr("id"); 224 if(flag==1){ 225 $(this).text("暫停"); 226 uploader.upload(uploader.getFile(id,true)); 227 228 }else{ 229 $(this).text("開始"); 230 //uploader.stop(true); 231 uploader.stop(uploader.getFile(id,true)); 232 //uploader.skipFile(file); 233 //uploader.removeFile(file); 234 //uploader.getFile(id,true); 235 } 236 }); 237 238 $("body").on("click","#uploadTable button[name='delete']",function(){ 239 var id=$(this).parents("tr.item").attr("id"); 240 $(this).parents("tr.item").remove(); 241 uploader.removeFile(uploader.getFile(id,true)); 242 map.remove(id); 243 }); 244 </script> 245 </body> 246 </html>
1 <!-- 2 list.html 3 --> 4 <!DOCTYPE html> 5 <html lang="zh-CN"> 6 <head> 7 <meta charset="utf-8"> 8 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 9 <meta name="viewport" content="width=device-width, initial-scale=1"> 10 <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> 11 <title>Bootstrap 101 Template</title> 12 13 <!-- Bootstrap --> 14 <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> 15 16 <!-- HTML5 shim 和 Respond.js 是爲了讓 IE8 支持 HTML5 元素和媒體查詢(media queries)功能 --> 17 <!-- 警告:經過 file:// 協議(就是直接將 html 頁面拖拽到瀏覽器中)訪問頁面時 Respond.js 不起做用 --> 18 <!--[if lt IE 9]> 19 <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script> 20 <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script> 21 <![endif]--> 22 <!-- jQuery (Bootstrap 的全部 JavaScript 插件都依賴 jQuery,因此必須放在前邊) --> 23 <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script> 24 <!-- 加載 Bootstrap 的全部 JavaScript 插件。你也能夠根據須要只加載單個插件。 --> 25 <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> 26 </head> 27 <body> 28 <div class="container-fluid"> 29 <div class="table-responsive col-md-6 col-md-offset-3"> 30 <table class="table"> 31 <tr> 32 <td class="active">序號</td> 33 <td class="active">文件</td> 34 </tr> 35 {% raw %}{% for file in files %} 36 <tr> 37 <td class="active">{{ files.index(file)+1 }}</td> 38 <td class="active">{{file}}</td> 39 </tr> 40 {% endfor %}{% endraw %} 41 </table> 42 </div> 43 </div> 44 </body> 45 </html>