原理如:3G的大文件分1500个2M二进度文件,通post方法发送给node服务,服务器全部接收到文件后,进组装生成你上文件。
需要了解以下node库,:
async: http://c7.gg/cdFxN
multiparty:http://c7.gg/cdFkN
客户端代码:
-
<div class="hei-bg" style="display:block;" >
-
<div class="user-info" style="display:block;" >
-
<div class="tc">请上传大文件</div>
-
<div class="user-pic picw320"><input id="uppic" type="file" ><img id="upimg" src="/img/bbb.jpg"></div>
-
<div id="jd" class="jdb">进度</div>
-
<div><div id="userbtn" class="bg-main tc userbtn">确定</div></div>
-
</div>
-
</div>
-
<script src="./res/js/lib/jquery.min.js"></script>
-
<script src="./res/js/lib/async.min.js"></script>//异步库
-
<script>
-
$(function(){
-
$('#userbtn').on('click',function(){
-
var file= $("#uppic")[0].files[0],//上传文件主体
-
name = file.name, //文件名
-
size = file.size, //总大小
-
succeed = 0; //当前上传数
-
var shardSize = 2 *1024*1024, //以2MB为一个分片
-
shardCount = Math.ceil(size / shardSize); //总片数
-
/*生成上传分片文件顺充,通过async.eachLimit()进行同步上传
-
attr里面是[0,1,2,3...,最后一位]
-
*/
-
var attr=[];
-
for(var i=0;i<shardCount;++i){
-
attr.push(i);
-
}
-
async.eachLimit(attr,1,function(item,callback){
-
var i=item;
-
var start = i * shardSize,//当前分片开始下标
-
end = Math.min(size, start + shardSize);//结束下标
-
//构造一个表单,FormData是HTML5新增的
-
var form = new FormData();
-
form.append("data", file.slice(start,end)); //slice方法用于切出文件的一部分
-
form.append("name", name);//文件名字
-
form.append("total", shardCount); //总片数
-
form.append("index", i + 1); //当前片数
-
//Ajax提交
-
$.ajax({
-
url: "/dafile",
-
type: "POST",
-
data: form,
-
timeout:120*1000,
-
async: false, //同步
-
processData: false, //很重要,告诉jquery不要对form进行处理
-
contentType: false, //很重要,指定为false才能形成正确的Content-Type
-
success: function(data){
-
++succeed;
-
var data=eval('('+data+')');
-
/*返回code为0是成功上传,1是请继续上传*/
-
if(data.code==0){
-
console.log(data.msg);
-
}else if(data.code==1){
-
console.log(data.msg);
-
}
-
//生成当前进度百分比
-
var jd=Math.round(succeed/shardCount*100)+'%';
-
$('.jdb').html(jd);
-
/*如果是线上,去掉定时,直接callback(),
-
这样写是为方便,本地测试看到进度条变化
-
因为本地做上传测试是秒传,没有时间等待*/
-
setTimeout(callback,50);
-
}
-
});
-
},function(err){
-
console.log('上传成功');
-
});
-
});
-
});
-
</script>
服务器代码:
-
function user(req,res,config){
-
var path=require('path');
-
var fs=require('fs');
-
var multiparty = require('multiparty');//文件上传模块
-
var async = require('async');//异步模块
-
var form = new multiparty.Form();//新建表单
-
//设置编辑
-
form.encoding = 'utf-8';
-
//设置文件存储路径
-
form.uploadDir = "Uploads/img/";
-
//设置单文件大小限制
-
// form.maxFilesSize = 200 * 1024 * 1024;
-
/*form.parse表单解析函数,fields是生成数组用获传过参数,files是bolb文件名称和路径*/
-
form.parse(req, function (err,fields,files) {
-
files=files['data'][0];//获取bolb文件
-
var index=fields['index'][0];//当前片数
-
var total=fields['total'][0];//总片数
-
var name=fields['name'][0];//文件名称
-
var url='Uploads/img/'+name+index;//临时bolb文件新名字
-
fs.renameSync(files.path,url);//修改临时文件名字
-
var pathname='Uploads/img/'+name;//上传文件存放位置和名称
-
if(index==total){//当最后一个分片上传成功,进行合并
-
/*
-
检查文件是存在,如果存在,重新设置名称
-
*/
-
fs.access(pathname,fs.F_OK,(err) => {
-
if(!err){
-
var myDate=Date.now();
-
pathname='Uploads/img/'+myDate+name;
-
console.log(pathname);
-
}
-
});
-
//这里定时,是做异步串行,等上执行完后,再执行下面
-
setTimeout(function(){
-
/*进行合并文件,先创建可写流,再把所有BOLB文件读出来,
-
流入可写流,生成文件
-
fs.createWriteStream创建可写流
-
aname是存放所有生成bolb文件路径数组:
-
['Uploads/img/3G.rar1','Uploads/img/3G.rar2',...]
-
*/
-
var writeStream=fs.createWriteStream(pathname);
-
var aname=[];
-
for(var i=1;i<=total;i++){
-
var url='Uploads/img/'+name+i;
-
aname.push(url);
-
}
-
//async.eachLimit进行同步处理
-
async.eachLimit(aname,1,function(item,callback){
-
//item 当前路径, callback为回调函数
-
fs.readFile(item,function(err,data){
-
if(err)throw err;
-
//把数据写入流里
-
writeStream.write(data);
-
//删除生成临时bolb文件
-
fs.unlink(item,function(){console.log('删除成功');})
-
callback();
-
});
-
},function(err){
-
if (err) throw err;
-
//后面文件写完,关闭可写流文件,文件已经成生完成
-
writeStream.end();
-
//返回给客服端,上传成功
-
var data=JSON.stringify({'code':0,'msg':'上传成功'});
-
res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'});
-
res.end(data);//返回数据
-
});
-
},50);
-
}else{//还没有上传文件,请继续上传
-
var data=JSON.stringify({'code':1,'msg':'继续上传'});
-
res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'});
-
res.end(data);//返回数据
-
}
-
});
-
return user;
-
};
-
exports.init = user;
-
这是初步设计方案,后期加异步上传和断点续传功能。。