关闭

基于node服务器的大文件(G级)上传

时间: 2018-05-02阅读: 1876标签: node

原理如:3G的大文件分1500个2M二进度文件,通post方法发送给node服务,服务器全部接收到文件后,进组装生成你上文件。

需要了解以下node库,:

async: http://caolan.github.io/async/ 
multiparty:https://www.npmjs.com/package/multiparty


客户端代码

<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;

//这是初步设计方案,后期加异步上传和断点续传功能。。



站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/725

关闭

Node.js是什么?及node的优缺点

Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js使用事件驱动,非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。

NodeJs实现简单的爬虫

爬虫,是一种按照一定的规则,自动地抓取网页信息的程序或者脚本;利用NodeJS实现一个简单的爬虫案例,脚本所用到的nodejs模块。express 用来搭建一个服务,将结果渲染到页面, swig模板引擎,cheerio用来抓取页面的数据

当node升级后导致webpack打包出错,node-saas出问题的解决办法

node-saas就需要python环境了,所以很多人又不知道,就升级了node,导致node-saas无法使用了,结果导致node-saas出错,解决办法如下:npm install -g node-gyp ,npm install --global --production windows-build-tools

node如何避免崩掉?

当你在node中没有处理reject状态的promise或在一个流中没有处理错误error事件,会引起你的程序崩溃。下面我们来看一下如何避免我们的node程序崩溃。

为什么要用 Node.js

传统意义上的 JavaScript 运行在浏览器上,这是因为浏览器内核实际上分为两个部分:渲染引擎和 JavaScript 引擎。前者负责渲染 HTML + CSS,后者则负责运行 JavaScript。Chrome 使用的 JavaScript 引擎是 V8,它的速度非常快。

把你的NodeJS程序给没有NodeJS的人运行

众所周知,NodeJS程序开发简便且容易实现跨平台。但是,当你开发了一个NodeJS程序,想要分发给其他人运行的时候,你会发现,你往往需要对方也来安装一个NodeJS环境

node.js中常用的fs文件系统

node.js中常用的fs文件系统:fs文件系统模块对于系统文件及目录进行一些读写操作。模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。

NodeJS沙盒逃逸研究

在这篇文章中,我们将探讨如何使用解释器的内部结构来逃离NodeJS沙箱。Node.js不是一个JavaScript框架,不同于CakePHP、Django、Rails。Node.js更不是浏览器端的库,不能与jQuery、ExtJS相提并论。

Node.js 中的流

Node.js 中的流(Stream)是出了名的难用甚至是难以理解。用 Dominic Tarr 的话来说:“流是 Node 中最好的,也是最容易被误解的想法。”即使是 Redux 的创建者和 React.js 的核心团队成员 Dan Abramov 也害怕 Node 流。

node.js反向代理的实现

在实际工程开发中,会有前后端分离的需求。使用node.js反向代理的目的:实现前后端分离,前端减少路径请求的所需的路由文件;通过http-proxy-middleware中间件、Http Proxy 模块这2种方式实现node.js的反向代理

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!