山东外贸行业网站开发,推广网站有什么方法,北京网站开开发公司电话,中国机械加工网19易0下6拉en文件下载
传统的文件下载有两种方法#xff1a;
使用a/标签#xff0c;href属性直接连接到服务器的文件路径window.location.hrefurl
这两种方法效果一样。但有个很大的问题#xff0c;如果下载出现异常#xff08;连接路径失效、文件不存在、网络问…文件下载
传统的文件下载有两种方法
使用a/标签href属性直接连接到服务器的文件路径window.location.hrefurl
这两种方法效果一样。但有个很大的问题如果下载出现异常连接路径失效、文件不存在、网络问题等会导致原本的页面被覆盖掉显示404等错误信息。
大致的优化思路如下
使用a/标签HTML5新的属性download。使用iframeiframe/元素进行下载。使用ajax、axios、fetch等方法异步下载。使用websocket下载。
我们来逐一分析 a/标签的download属性需要和href一起用download的作用是为下载的文件赋文件名。 如果服务端没有指定文件名就以此属性规定的名称命名。如果下载出现异常该属性的存在能够保证页面不会出问题。如果服务端返回的不是文件、而是字符如果download‘’error.txt”能够通过打开此文件查看到返回的文本信息。iframe标签可以做到在现有的页面下内嵌一个子页面。当用户点击文件下载时将隐藏的iframe元素的src属性指向文件下载路径。 如果没有异常文件将会直接下载。如果出现异常iframe子页面会报错父页面不会受任何影响。使用异步请求进行下载。 在网上看了看大致的流程是发送异步请求时设置responseType为blob即接收流数据为blob对象保存在内存中。接收完成后生成链接地址1.通过FileReader对象将blob对象生成base64编码 2.通过URL.createObjectURL生成指向文件内存的链接写入a/标签的href属性然后模拟点击a/按标签实现下载。此方法最大的问题是因无法直接操作磁盘故接收的文件必须先存放在内存中且只有传输完成后才能构建blob对象才能转化成文件。因此大文件的下载可能会把你的浏览器挤爆。使用websocket下载。 需要额外开启websocket服务此方法未做实践。
总结以上方法最推荐前两种方便简单。
附上后端Django代码适用于前两种方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 def syncDownLoad(request): 文件下载 print(同步下载文件) startTime time.time() def file_iterator(file, chunk_size1024): with open(file, rb) as f: while True: c f.read(chunk_size) if c: yield c else: endTime time.time() print(传输时间, endTime - startTime) break fileRoute /static/files/2018/12/18/第四章1学习动机概述.mp4 fileName 第四章1学习动机概述.mp4 route os.path.dirname(os.path.dirname(__file__)) fileRoute if os.path.exists(route): # 如果存在文件 response StreamingHttpResponse(file_iterator(route)) # response[Content-Type] application/octet-stream response[Content-Type] text/html response[Content-Disposition] attachment;filename{0}.format(fileName).encode(utf-8) return response else: return HttpResponse(cannot find file)
参考链接
https://scarletsky.github.io/2016/07/03/download-file-using-javascript/
https://my.oschina.net/watcher/blog/1525962 文件上传 概述
文件上传需要处理的问题有
1.多文件上传 2.异步上传 3.拖拽上传 4.上传限制限制大小、类型 5.显示上传进度、上传速度、中途取消上传 6.预览文件
HTML DEMO 1 2 input typefile idfile namemyfile onchangeonchanges() multiplemultiple/ input typebutton onclickSerialUploadFile() value上传/
一、多文件上传 1 input typefile idfile namemyfile multiplemultiple/ !-- multiple属性 --
二、异步上传
通过ajax等方式异步上传FormData对象支持传输文件。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 function UploadFile() { var fileObj document.getElementById(file).files; // js 获取文件对象(FileList对象) // FormData 对象 var form new FormData(); form.append(author, xueba); // 可以增加表单数据 for (let i 0; i fileObj.length; i) { form.append(file, fileObj[i]); // 文件对象 } $.ajax({ url: /file_upload/, type: POST, async: true, // 异步上传 data: form, contentType: false, // 必须false才会自动加上正确的Content-Type processData: false, // 必须false才会避开jQuery对 formdata 的默认处理。XMLHttpRequest会对 formdata 进行正确的处理 success: function (data) { data JSON.parse(data); data.forEach((i){ console.log(i.code,i.file_url); }); }, error: function () { alert(aaa上传失败); }, }); }
三、拖拽上传
默认文本、图像和链接可以被拖动。其它的元素想要被拖动只需为标签加一个draggabletrue属性 1 div draggabletruediv/ HTML5 API drag 和 drop 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 被拖动元素发生的事件 dragstart 被拖动元素开始拖动时 drag 正在被拖动时 dragend 取消拖拽时 目标元素发生的事件(当某元素被绑定以下事件就变成了目标元素) dragenter 拖动元素进入目标上触发 dragover 拖动元素在目标元素上移动触发 dragleave 拖动元素离开目标时触发 drop 拖动元素在目标上释放触发这时不会触发dragleave 注意 1.目标元素默认不能够被拖放drop要在dragover事件中取消默认事件(e.preventDefault()) 2.有些元素(img)被拖放后默认以链接形式打开,要在drop事件中取消默认事件(e.preventDefault()) 【火狐浏览器可能不顶用需要再加event.stopPropagation()】 dataTransfer(事件对象属性(对象)) 数据交换只是简单的拖拽没有意义我们还需要数据交换即被拖动元素和目标元素之间的数据交换。 方法 setData(key,value) 设置数据(key和value都必须是string类型) getData(key) 获取数据 clearData() 清除数据(不传参清空所有数据) setDragImage(imgElement,x,y) 设置元素移动过程中的图像(参数:图像元素,xy表示图像内的偏移量) 属性 dropEffect 表示被拖动元素可以执行哪一种放置行为(一般在dragover事件内设置) none禁止放置(默认值) move移动到新的位置 copy复制到新的位置 link effectAllowed 用来指定拖动时被允许的行为(一般无需设置) copymovelinkcopyLinkcopyMovelinkMoveallnoneuninitialized默认值,相当于all. files FileList对象。如果拖动的不是文件此为空列表 items 返回DataTransferItems对象该对象代表了拖动数据。 types 返回一个DOMStringList对象该对象包括了存入dataTransfer中数据的所有类型。 注意 1.如果拖拽了文本浏览器会自动调用setData()设置对应文本数据
参考链接
https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_Drag_and_Drop_API
https://developer.mozilla.org/zh-CN/docs/Web/API/DataTransfer
https://www.zhangxinxu.com/wordpress/2018/09/drag-drop-datatransfer-js/
http://www.sohu.com/a/198973397_291052
四、上传限制 1 input typefile acceptimage/* / 接收全部格式的图片
此外获取到的File对象中有type属性可以得知文件类型size属性的得知文件大小
五、上传进度、上传速度、中途取消上传
原生API 1 2 3 4 5 6 7 8 9 10 11 12 xhr.onload function(e){}//上传请求完成 xhr.onerror function(e){}//上传异常 xhr.upload.onloadstart function(e){}//开始上传 xhr.upload.onprogress function(e){};//上传进度 这个方法会在文件每上传一定字节时调用 e.loaded//表示已经上传了多少byte的文件大小 e.total//表示文件总大小为多少byte 通过这两个关键的属性就可以去计算 上传进度与速度 xhr.onreadystatechange function(){}//当xhr的状态上传开始结束失败变化时会调用 该方法可以用来接收服务器返回的数据 中途取消上传 xhr.abort();
单文件上传 或 多文件串行上传 Demo该Demo只会有一个进度条显示上传总进度。对应“异步上传”的代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 xhr.upload.addEventListener(progess,progessSFunction,false); // 上传过程中显示进度和速度 function progressSFunction(e) { var progressBar document.getElementById(pro); var percentageDiv document.getElementById(per); if (e.lengthComputable) // lengthComputable表示进度信息是否可用 { progressBar.max e.total; progressBar.value e.loaded; let speed (e.loaded - progress[0].last_laoded) / (e.timeStamp - progress[0].last_time) bytes/s; let percent Math.round(e.loaded / e.total * 100) %; progress[0].last_laoded e.loaded, progress[0].last_time e.timeStamp; percentageDiv.innerHTML percent speed; } }
多文件并行上传进度显示多个进度条分别上传 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 // 多文件并行上传 function ParallelUploadFile() { last_laoded 0; last_time (new Date()).getTime(); var fileObj document.getElementById(file).files; // js 获取文件对象 for (let k 0; k fileObj.length; k) { let domStr div ${fileObj[k].name}大小${fileObj[k].size}字节 progress classprogressBar idpro${k} value max/progress span classpercentage idper${k}/span /div; $(body).append(domStr); // FormData 对象 var form new FormData(); form.append(author, xueba); // 可以增加表单数据 form.append(csrfmiddlewaretoken, $([name csrfmiddlewaretoken]).val()); form.append(file, fileObj[k]); // XMLHttpRequest 对象 {#var xhr new XMLHttpRequest();#} {#xhr.open(post, /file_upload/, true);#} {#xhr.onload function () {#} {# alert(上传完成!);#} {# };#} {#xhr.upload.addEventListener(progress, progressFunction, false);#} {#xhr.send(form);#} // jQuery ajax $.ajax({ url: /file_upload/, type: POST, async: true, // 异步上传 data: form, contentType: false, // 必须false才会自动加上正确的Content-Type processData: false, // 必须false才会避开jQuery对 formdata 的默认处理。XMLHttpRequest会对 formdata 进行正确的处理 xhr: function () { let xhr $.ajaxSettings.xhr(); xhr.upload.addEventListener(progress, (e) {progressPFunction(e, k)}, false); xhr.upload.onloadstart (e) { progress[k] { last_laoded: 0, last_time: e.timeStamp, }; }; xhr.upload.onloadend () { delete progress[k]; }; return xhr; }, success: function (data) { data JSON.parse(data); data.forEach((i) { console.log(i.code, i.file_url); }); }, error: function () { alert(aaa上传失败); }, }); } }
六、预览文件
预览图片 1 2 3 4 5 6 7 8 9 10 11 12 13 function onchanges() { // input file绑定onchange事件 let files document.getElementById(file).files; if(files[0].type.indexOf(image)-1) { let read new FileReader(); read.onload function(e) { // 读取操作完成时触发 let img new Image(); img.src e.target.result; // 将base64编码赋给src属性 $(body)[0].appendChild(img); }; read.readAsDataURL(files[0]); // 读取文件转化成base64编码 } }
七、前后端汇总Demo
前端
HTML 1 2 input typefile idfile namemyfile onchangeonchanges() multiplemultiple/ input typebutton onclickSerialUploadFile() value上传/
JavaScript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 let progress {}; let last_laoded; let last_time; function onchanges() { let files document.getElementById(file).files; console.log(共${files.length}个文件); let countSize 0; for (let i 0; i files.length; i) { console.log(${files[i].name} 大小${files[i].size}); countSize files[i].size; } console.log(共计占用${countSize}字节); if (files[0].type.indexOf(image) -1) { let read new FileReader(); read.onload function (e) { // 读取操作完成时触发 let img new Image(); img.src e.target.result; // 将base64编码赋给src属性 $(body)[0].appendChild(img); }; read.readAsDataURL(files[0]); // 读取文件转化成base64编码 } } // 多文件并行上传 function ParallelUploadFile() { last_laoded 0; last_time (new Date()).getTime(); var fileObj document.getElementById(file).files; // js 获取文件对象 for (let k 0; k fileObj.length; k) { let domStr div ${fileObj[k].name}大小${fileObj[k].size}字节 progress classprogressBar idpro${k} value max/progress span classpercentage idper${k}/span /div; $(body).append(domStr); // FormData 对象 var form new FormData(); form.append(author, xueba); // 可以增加表单数据 form.append(csrfmiddlewaretoken, $([name csrfmiddlewaretoken]).val()); form.append(file, fileObj[k]); // XMLHttpRequest 对象 {#var xhr new XMLHttpRequest();#} {#xhr.open(post, /file_upload/, true);#} {#xhr.onload function () {#} {# alert(上传完成!);#} {# };#} {#xhr.upload.addEventListener(progress, progressFunction, false);#} {#xhr.send(form);#} // jQuery ajax $.ajax({ url: /file_upload/, type: POST, async: true, // 异步上传 data: form, contentType: false, // 必须false才会自动加上正确的Content-Type processData: false, // 必须false才会避开jQuery对 formdata 的默认处理。XMLHttpRequest会对 formdata 进行正确的处理 xhr: function () { let xhr $.ajaxSettings.xhr(); xhr.upload.addEventListener(progress, (e) {progressPFunction(e, k)}, false); xhr.upload.onloadstart (e) { progress[k] { last_laoded: 0, last_time: e.timeStamp, }; }; xhr.upload.onloadend () { delete progress[k]; }; return xhr; }, success: function (data) { data JSON.parse(data); data.forEach((i) { console.log(i.code, i.file_url); }); }, error: function () { alert(aaa上传失败); }, }); } } // 多文件串行上传 function SerialUploadFile() { var fileObj document.getElementById(file).files; // js 获取文件对象 let domStr div progress classprogressBar idpro value max/progress span classpercentage idper/span /div; $(body).append(domStr); // FormData 对象 var form new FormData(); form.append(author, xueba); // 可以增加表单数据 for (let i 0; i fileObj.length; i) { form.append(file, fileObj[i]); // 文件对象 } // jQuery ajax $.ajax({ url: /file_upload/, type: POST, async: true, // 异步上传 data: form, contentType: false, // 必须false才会自动加上正确的Content-Type processData: false, // 必须false才会避开jQuery对 formdata 的默认处理。XMLHttpRequest会对 formdata 进行正确的处理 xhr: function () { let xhr $.ajaxSettings.xhr(); xhr.upload.addEventListener(progress, progressSFunction, false); xhr.upload.onloadstart (e) { progress[0] { last_laoded: 0, last_time: e.timeStamp, }; console.log(开始上传,progress); }; xhr.upload.onloadend () { delete progress[0]; console.log(结束上传,progress); }; return xhr; }, success: function (data) { data JSON.parse(data); data.forEach((i) { console.log(i.code, i.file_url); }); }, error: function () { alert(aaa上传失败); }, }); } // jQuery版本进度条 function Progressbar(e) { var bar $(#progressBar); // 进度条 var num $(#percentage); // 百分比 if (e.lengthComputable) { bar.attr(max, e.total); bar.attr(value, e.loaded); num.text(Math.round(e.loaded / e.total * 100) %); } } // 原生js版 并行进度条 function progressPFunction(e, k) { var progressBar document.getElementById(pro${k}); var percentageDiv document.getElementById(per${k}); if (e.lengthComputable) { progressBar.max e.total; progressBar.value e.loaded; let speed (e.loaded - progress[k].last_laoded) / (e.timeStamp - progress[k].last_time) bytes/s; let percent Math.round(e.loaded / e.total * 100) %; progress[k].last_laoded e.loaded, progress[k].last_time e.timeStamp; percentageDiv.innerHTML percent speed; console.log(speed); } } // 原生js 串行进度条 function progressSFunction(e) { var progressBar document.getElementById(pro); var percentageDiv document.getElementById(per); if (e.lengthComputable) // lengthComputable表示进度信息是否可用 { progressBar.max e.total; progressBar.value e.loaded; let speed (e.loaded - progress[0].last_laoded) / (e.timeStamp - progress[0].last_time) bytes/s; let percent Math.round(e.loaded / e.total * 100) %; progress[0].last_laoded e.loaded, progress[0].last_time e.timeStamp; percentageDiv.innerHTML percent speed; } }
Django后端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def file_upload(request): ajax文件上传功能 resList, fileList [], request.FILES.getlist(file) dir_path static/files/{0}/{1}/{2}.format(time.strftime(%Y),time.strftime(%m),time.strftime(%d)) if os.path.exists(dir_path) is False: os.makedirs(dir_path) for file in fileList: file_path %s/%s % (dir_path, file.name) file_url /%s/%s % (dir_path, file.name) res {code: 0, file_url: } with open(file_path, wb) as f: if f False: res[code] 1 for chunk in file.chunks(): # chunks()代替read(),如果文件很大可以保证不会拖慢系统内存 f.write(chunk) res[file_url] file_url resList.append(res) return HttpResponse(json.dumps(resList))
参考
https://www.cnblogs.com/potatog/p/9342448.html
https://www.w3cmm.com/ajax/progress-events.html
文章来源https://www.cnblogs.com/V587Chinese/p/11371380.html