js⼤⽂件上传详解及实例代码
⽂件夹上传:从前端到后端
⽂件上传是 Web 开发肯定会碰到的问题,⽽⽂件夹上传则更加难缠。⽹上关于⽂件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架⽂件上传的⽂章⼜不会涉及⽂件夹。今天研究了⼀下这个问题,在此记录。
先说两个问题:
是否所有后端框架都⽀持⽂件夹上传?
是否所有浏览器都⽀持⽂件夹上传?
第⼀个问题:YES,第⼆个问题:NO
只要后端框架对于表单的⽀持是完整的,那么必然⽀持⽂件夹上传。⾄于浏览器,截⾄⽬前,只有 Chrome ⽀持。
如果需要其它的浏览器⽀持则需要借助于插件,⽐如泽优⼤⽂件上传控件:
关于WebUploader的功能说明:
⼤⽂件上传续传
⽀持超⼤⽂件上传(100G+)和续传,可以关闭浏览器,重启系统后仍然继续上传。
开源
提供ASP.NET,JSP,PHP⽰例和源代码,其中JSP提供MySQL,Oracle,SQL Server数据库的配置和⽰例代码。
分⽚、并发
分⽚与并发结合,将⼀个⼤⽂件分割成多块,并发上传,极⼤地提⾼⼤⽂件的上传速度。
当⽹络问题导致传输错误时,只需要重传出错分⽚,⽽不是整个⽂件。另外分⽚传输能够更加实时的跟踪上传进度。
预览、压缩
⽀持常⽤图⽚格式jpg,jpeg,gif,bmp,png预览与压缩,节省⽹络数据传输。
解析jpeg中的meta信息,对于各种orientation做了正确的处理,同时压缩后上传保留图⽚的所有原始meta数据。
多途径添加⽂件
⽀持⽂件多选,类型过滤,拖拽(⽂件&⽂件夹),图⽚粘贴功能。上传本地指定路径的⽂件,不需要通过点击按钮选择⽂件。
粘贴功能主要体现在当有图⽚数据在剪切板中时(截屏⼯具如QQ(Ctrl + ALT + A), ⽹页中右击图⽚点击复制),Ctrl + V便可添加此图⽚⽂件。
HTML5 & FLASH
兼容主流浏览器和低版本浏览器,接⼝⼀致,实现了两套运⾏时⽀持,⽤户⽆需关⼼内部⽤了什么内核。⽽且⽀持IE6,IE8浏览器。
同时Flash部分没有做任何UI相关的⼯作,⽅便不关⼼flash的⽤户扩展和⾃定义业务需求。
基于内存映射模式进⾏IO操作,充分发挥操作系统性能。
MD5秒传
当⽂件体积⼤、量⽐较多时,⽀持上传前做⽂件md5值验证,⼀致则可直接跳过。
如果服务端与前端统⼀修改算法,取段md5,可⼤⼤提升验证性能,耗时在20ms左右。
易扩展、可拆分
采⽤可拆分机制, 将各个功能独⽴成了⼩组件,可⾃由搭配。
采⽤AMD规范组织代码,清晰明了,⽅便⾼级玩家扩展。
⽂件夹上传
⽀持10万+级别的⽂件夹上传,续传。
⽀持层级⽬录结构保存,上传后能够将数据库层级信息保存在数据库中。
提供MySQL,Oracle,SQL Server数据库⽀持。
⽀持⽂件夹续传,在浏览器刷新,重启后仍然能够继续上传。
⽀持跨域上传。
PC端全平台⽀持
⽀持Windows,macOS,Linux。⽀持国产化操作系统,⽀持政务信息安全项⽬。
其中Windows⽀持低版本系统:Windows XP。
其中浏览器包括:IE6,IE7,IE8(x86,x64),IE9(x86,x64),IE10(x86,x64),IE11(x86,x64),360安全浏览器,360极速浏览器,QQ浏览器,搜狗浏览器,Maxthon(遨游)浏览器1.X,Maxthon(傲游)浏览器2.x,Firefox,Chrome,Opera 23+
选择⽂件夹进⾏上传
⽂件夹上传完毕
⽂件夹上传后在服务器中的层级结构
好,假定我们的所有⽤户都⽤上了 Chrome,要怎么做才能成功上传⼀个⽂件夹呢?这⾥不⽤drop这种⾼⼤上的东西,就⽤最传统的
<input>。⽤表单 submit 和 ajax 都可以做,先看 submit ⽅式。
<form method="POST" enctype=multipart/form-data>
<input type='file' name="file" webkitdirectory >
<button>upload</button>
</form>
我们只要添加上 webkitdirectory 这个属性,在选择的时候就可以选择⼀个⽂件夹了,如果不加,⽂件夹被选中的时候就是灰⾊的。不过貌似加上这个属性就没法选中⽂件了... enctype=multipart/form-data 也是必要的,解释参见这⾥:
ajax实例 文件浏览
如果⽤ ajax ⽅式,我们可以省去<form>,只留下<input>就 OK。
<input type='file' webkitdirectory >
<button id="upload-btn" type="button">upload</button>
但是这样是不够的,关键在于 Js 的使⽤。
var files = [];
$(document).ready(function(){
$("input").change(function(){
files = this.files;
});
});
$("#upload-btn").click(function(){
var fd = new FormData();
for (var i = 0; i < files.length; i++) {
fd.append("file", files[i]);
}
$.ajax({
url: "/upload/",
method: "POST",
data: fd,
contentType: false,
processData: false,
cache: false,
success: function(data){
console.log(data);
}
});
});
⽤ ajax ⽅式,我们必须⼿动构造⼀个 FormData Object, 然后放在 data ⾥⾯提交到后端。 FormData 好像就只有⼀个 append ⽅法,第⼀个参数是 key,第⼆个参数是 value,⽤来构造表单数据。ajax请求中,通过 input 元素的 files 属性获取上传的⽂件。files属性不论加不加webkitdirectory 都是存在的,⽤法也基本⼀样。不过当我们上传⽂件夹时,files 中会包含⽂件相对路径的信息,之后会看到。
⽤ ajax 上传的好处有两点,⾸先是异步,这样不会导致页⾯卡住,其次是能⽐较⽅便地实现上传进度条。关于上传进度条的实现可以参考这⾥。需要注意的是contentType和processData必须设置成false,参考了这⾥: