【组件开发】html5版断点续传【二】---前后端代码

界面及模板代码

【包含组件调用方式--借鉴了huploadify的部分代码,向huploadify作者致敬。】

   <script type="text/javascript" src="/static/UI/Huploadify3.0/jquery.Huploadify.v3.js"></script>
    <style type="text/css">
    </style>
    <script type="text/javascript">
        $(function(){
            var up = $('#upload').Huploadify({

                /**---上传按钮ui设置--**/
                fileInputId:"fileInput",//文本上传框的id。
                fileButtonTPL:document.getElementById("tpl_filebutton").innerHTML ,//模板字符串,请注意,这里用的模板引擎是laytpl,请使用laytpl的语法来写模板,具体可以参考demo页面的写法。
                fileBrowserButtonId:"fileBrowserButton",//用于遮住文本框的按钮的id。
                fileTypeExts:'*.*',//允许上传的文件类型,格式'*.jpg;*.doc'
                buttonText:'选择文件',//上传按钮上的文字
                multi:true,

                /**列表模板**/
                queuePanelId:"filelist",
                fileQueueTPL:document.getElementById("tpl_filequeue").innerHTML,//文件列表的模板,请注意它也是用laytpl渲染的,注意语法,而且有几个文件列表里面有几个组件不能缺少(你可以隐藏他们)--除非你设置showFileQueue=false--否则,进度条,上传按钮,删除按钮请不要去掉了。



                formData:{key:123456,key2:'vvvv'},
                fileSizeLimit:99999999999,
                showUploadedPercent:false,
                showUploadedSize:true,
                removeTimeout:9999999,
                uploader:'handler_chunkuploader.jsp',
                breakPoints:true,
                fileSplitSize:1024*1024//断点续传的文件块大小,单位Byte,默认1M
                //--几个方法设置。
                ,onBeforeSendBlob:function(fileMD5,chunkSequence,paras){
                    paras.chunks_seq=chunkSequence;
                    paras.chunk=chunkSequence;
                    paras.md5=fileMD5;
                    console.log(" before send blob: "+fileMD5+" chunk "+chunkSequence);
                }


                ,onAfterSendBlob:function(fileMD5,chunkSequence,isIgnore){
                    console.log("after send blob:"+fileMD5+" chunk "+chunkSequence+" ingnore "+isIgnore);
                }
                ,onBeforeSendFile:function(fileMD5){
                    console.log("before send file:"+fileMD5);

                }
                ,onAfterSendFile:function(fileMD5,fileInfo){
                    console.log("after send file:"+fileMD5);
                    $.ajax({
                        url:"handler_combineChunks.jsp",
                        data:{
                            md5:fileMD5,
                            total:fileInfo.chunks,
                            name:fileInfo.fileName
                        },
                        success:function(data){
                            console.log("合并文件结果");
                            console.log(data);
                        }


                    });
                }

            });

            $("#btn_upload").click(function(){
               up.upload();
            });
            window.up=up;
        });
    </script>
</head>

<body>
<div id="upload"></div>
<div id="filelist" class="uploadify-queue">

</div>
<div>
    <button id="btn_upload">开始上传</button>
</div>

<script type="text/html"  id="tpl_filebutton">
    {{#
    var item=d;
    var _multi="";
    if(item.multi){
    _multi=" multiple='' ";
    }
    var _accept=" accept='"+item.fileTypeExts+"' ";
    }}
    <input id="{{item.fileInputId}}" class="selectbtn" style="display:none;" type="file" name="fileselect[]" {{_multi}} {{_accept}} />
    <a id="{{item.fileBrowserButtonId}}" href="javascript:void(0)" class="uploadify-button">{{item.buttonText}}</a>
</script>

<script type="text/html" id="tpl_filequeue">

    {{#
    var items=d.items;
    if(items != undefined && items.length > 0){

            for(var i=0;i < items.length;i++){

    var item=items[i];
    var _showUploadBtn="display:inline-block;";
    if(item.file==null||item.file==undefined){

    _showUploadBtn="display:none";

    }
    var _uploadedSize=(item.chunks <= 0)?0:item.fileSize*(item.uploadedChunks/item.chunks);


    }}
    <div _md5="{{item.md5}}" class="uploadify-queue-item">
        <div class="uploadify-progress" lastloaded="609789">
            <div class="uploadify-progress-bar" style="width: {{item.percent}}%;"></div>
        </div>
        <span class="up_percent">{{item.percent}}%</span>
        <span class="progressnum">
        <span class="uploadedsize">{{d.F.formatFileSize(_uploadedSize,false)}}</span>/<span class="totalsize">{{d.F.formatFileSize(item.fileSize,false)}}</span></span>
        <span class="up_filename">{{item.fileName}}</span>

        【<span class="upload_status">请再次选择文件</span>】
        <!--<button class="uploadbtn" _md5="{{item.md5}}" style="{{_showUploadBtn}}">上传</button>-->
        <button class="delfilebtn" _md5="{{item.md5}}">删除</button>

    </div>

    {{#

    }

    }
    }}

</script>



js脚本代码

【注意,这个js使用了html5的特性,有文件切片,本地存储,所以,低版本的浏览器,ie9或者以上是不需要考虑的了。未来可能会考虑开发flash版本以作兼容。】


/**
 * Created by edward on 2014/10/24.
 * 该插件改自jquery.Huploadify 2.0,最大的特点是:
 * 1、将显示模板分离出来放在页面上面,随意修改(但是涉及到id就不要修改了,html结构可以改)。上传按钮,文件列表等都可以自定义结构样式。
 * 2、更新设置,现在可以随意设置要不要显示文件列表了,可以设置文件列表会显示到什么地方了。
 * 3、可以设置是否自动开始了,也修正本地保存的已经上传的文件列表的存储方式,改为存储md5码。。
 * 4、添加上传每一块之前的事件,添加自定义事件来控制是否跳过该chunk。
 *
 */
(function($){
    $.fn.Huploadify = function(opts){

        //--通用变量
        var _that=this;
        //-组件设置
        var defaults = {


            /**---上传按钮ui设置--**/
            fileInputId:"fileInput",//文本上传框的id。
            fileButtonTPL:"" ,//模板字符串,请注意,这里用的模板引擎是laytpl,请使用laytpl的语法来写模板,具体可以参考demo页面的写法。
            fileBrowserButtonId:"fileBrowserButton",//用于遮住文本框的按钮的id。
            fileTypeExts:'*.*',//允许上传的文件类型,格式'*.jpg;*.doc'
            buttonText:'选择文件',//上传按钮上的文字


            /**--上传列表ui设置--**/
            showFileQueue:true,//是否显示文件列表,假如显示的话,那么系统将按照模板将文件列表渲染到列表容器里面,再添加一些事件。
            queuePanelId:"queuePanel",//存放上传文件列表的容器的id,假如你不需要显示文件列表及上传进度,那么你就不需要特别指定这个东西了,它将不起作用。
            fileQueueTPL:"",//文件列表的模板,请注意它也是用laytpl渲染的,注意语法,而且有几个文件列表里面有几个组件不能缺少(你可以隐藏他们)--除非你设置showFileQueue=false--否则,进度条,上传按钮,删除按钮请不要去掉了。

            showUploadedPercent:true,//是否实时显示上传的百分比,如20%
            showUploadedSize:false,//是否实时显示已上传的文件大小,如1M/2M
            removeTimeout: 1000,//上传完成后进度条的消失时间,单位毫秒


            /**---其他功能设置--**/
            multi:true,//是否允许选择多个文件
            formData:null,//发送给服务端的参数,格式:{key1:value1,key2:value2}
            fileObjName:'file',//在后端接受文件的参数名称,如PHP中的$_FILES['file']
            fileSizeLimit:2048,//允许上传的文件大小,单位KB
            uploader:'',//文件提交的地址
            auto:false,//是否开启自动上传
            method:'post',//发送请求的方式,get或post
            //itemTemplate:itemTemp,//上传队列显示的模板--该参数丢弃
            fileSplitSize:1024*1024//断点续传的文件块大小,单位Byte,默认1M
            ,storageKey:"huploadify_storage" //保存到本地的key,请注意,假如你希望不同的组件保存不同的文件信息,那么就修改一下这个位置。


            //--几个方法设置。
            ,onBeforeSendBlob:function(fileMD5,chunkSequence,paras){
            }


            ,onAfterSendBlob:function(fileMD5,chunkSequence,isIgnore){

            }
            ,onBeforeSendFile:function(fileMD5,fileInfo){

            }
            ,onAfterSendFile:function(fileMD5,fileInfo){

            }

            /**相关提醒及提示**/

        };

        var defaults = $.extend(defaults,opts);

        //--相关模板引擎。
        var _tpl_button=laytpl(defaults.fileButtonTPL);
        var _tpl_list=laytpl(defaults.fileQueueTPL);


        //定义一个通用函数集合
        var F = {
            //将文件的单位由bytes转换为KB或MB,若第二个参数指定为true,则永远转换为KB
            formatFileSize : function(size,withKB){
                if (size > 1024 * 1024 && !withKB){
                    size = (Math.round(size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
                }
                else{
                    size = (Math.round(size * 100 / 1024) / 100).toString() + 'KB';
                }
                return size;
            },
            //将输入的文件类型字符串转化为数组,原格式为*.jpg;*.png
            getFileTypes : function(str){
                var result = [];
                var arr1 = str.split(";");
                for(var i=0, len=arr1.length; i<len; i++){
                    result.push(arr1[i].split(".").pop());
                }
                return result;
            },
            //根据文件序号获取文件
            getFile : function(index,files){
                for(var i=0;i<files.length;i++){
                    if(files[i].index == index){
                        return files[i];
                    }
                }
                return null;
            },
            //根据后缀名获取文件Mime类型
            getMimetype : function(name){
                var mimetypeMap = {
                    zip : ['application/x-zip-compressed'],
                    jpg : ['image/jpeg'],
                    png : ['image/png'],
                    gif : ['image/gif'],
                    doc : ['application/msword'],
                    xls : ['application/msexcel'],
                    docx : ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
                    xlsx : ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
                    ppt : ['application/vnd.ms-powerpoint'],
                    pptx : ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
                    mp3 : ['audio/mp3'],
                    mp4 : ['video/mp4'],
                    pdf : ['application/pdf']
                };
                return mimetypeMap[name];
            },
            //获取上传组件accept的值
            getAcceptString : function(str){
                var types = F.getFileTypes(str);
                var result = [];
                for(var i=0,len=types.length;i<len;i++){
                    var mime = F.getMimetype(types[i]);
                    if(mime){
                        result.push(mime);
                    }
                }
                return result.join(',');
            }
            //--将模板字符串渲染出来。
            ,renderButtonTPL:function(){
                var _tpl_str=defaults.fileButtonTPL;
                var d={
                    fileInputId:defaults.fileInputId,
                    fileBrowserButtonId:defaults.fileBrowserButtonId,
                    buttonText:defaults.buttonText,
                    fileTypeExts:defaults.fileTypeExts,
                    multi:defaults.multi
                };
                var tpl=laytpl(_tpl_str);
                var html=tpl.render(d);
                return html;
            }
            ,_filter: function(files) {		//选择文件组的过滤方法
                var arr = [];
                var typeArray = F.getFileTypes(defaults.fileTypeExts);
                if(typeArray.length>0){
                    for(var i=0,len=files.length;i<len;i++){
                        var f = files[i];
                        if(parseInt(F.formatFileSize(f.size,true))<=defaults.fileSizeLimit){
                            if($.inArray('*',typeArray)>=0 || $.inArray(f.name.split('.').pop(),typeArray)>=0){
                                arr.push(f);
                            }
                            else{
                                alert('文件 "'+f.name+'" 类型不允许!');
                            }
                        }
                        else{
                            alert('文件 "'+f.name+'" 大小超出限制!');
                            continue;
                        }
                    }
                }
                return arr;
            }
        };
        //--文件上传状态枚举值。
        var FileUploadStatus={
            ready:"ready",
            uploading:"uploading",
            cancel:"cancel",
            finished:"finished"
        };

        //--核心数据。
        var _fileUploadInfo={
            storageKey:defaults.storageKey//本地存储名称
            ,maxRecord:20 //最大记录条数,20.
            ,chunkSize:defaults.fileSplitSize //分块大小 5mb,最小单位为byte。
            ,files:[] //文件上传列表,里面的信息请参考下面的_fileInfo,在存储上面。fileInfo里面没有文件句柄file的参数,但是在运行时条件就必须有file这个句柄。
        };
        var _fileInfo={
            md5:"" //md5码
            ,fileName:"" //文件名称
            ,fileSize:0 //文件大小
            ,lastModified: 1413766748000 //最近修改日期
            ,chunks:0 //文件分块数量
            ,uploadstatus:FileUploadStatus.ready //文件上传状态。
            ,file:null //文件句柄
            ,fileType:""
            ,percent:0 //上传的进度
            ,uploadedChunks:0 //已经上传了的分片数量
            ,uploaded:[] //文件已经上传了的分块序号列表
        };

        var _memoryFiles=[];//这是内存里面文件上传列表,里面的文件都包含了文件句柄,切记。
        var _memoryFileInfo={
            md5:"" //md5码
            ,fileName:"" //文件名称
            ,fileSize:0 //文件大小
            ,lastModified: 1413766748000 //最近修改日期
            ,chunks:0 //文件分块数量
            ,uploadstatus:FileUploadStatus.ready //文件上传状态。
            ,file:null //文件句柄
            ,fileType:""
            ,status:""
            ,percent:0
            ,uploadedChunks:0 //已经上传了的分片数量
            ,uploaded:[] //文件已经上传了的分块序号列表
        };
        //--任务队列。
        /**
         * 本地任务队列解释:
         * 本地任务队列用于存储分片信息。
         * */
        var _taskQueue={
            status:"ready" //任务有几种状态,begin 开始,finished 结束 cancel 取消 ready 就绪
        };//格式如下:{md5_fileMD5:{chunk1:""}};以这个作为key。。以chunk1作为key。
        var __taskItem={

        };//当前任务的一些信息,只作为参考用的数据样本。
        //--任务队列管理器。
        var taskQueueManager={
            //--添加任务。
            addTask:function(fileMD5,sequence,begin,end){
                if(_taskQueue["md5_"+fileMD5]!=undefined&&_taskQueue["md5_"+fileMD5]["chunk_"+sequence]!=undefined){
                    _taskQueue["md5_"+fileMD5]["chunk_"+sequence]["begin"]=begin;
                    _taskQueue["md5_"+fileMD5]["chunk_"+sequence]["end"]=end;
                }
                else if(_taskQueue["md5_"+fileMD5]!=undefined){
                    _taskQueue["md5_"+fileMD5]["chunk_"+sequence]={
                        md5:fileMD5,
                        chunk:sequence,
                        begin:begin,
                        end:end
                    };
                }
                else{
                    _taskQueue["md5_"+fileMD5]={};
                    _taskQueue["md5_"+fileMD5]["chunk_"+sequence]={
                        md5:fileMD5,
                        chunk:sequence,
                        begin:begin,
                        end:end
                    };
                }

            }
            //--是否包含这个任务的信息。
            ,hasTask:function(fileMD5){
                if(_taskQueue["md5_"+fileMD5]==undefined){
                    return false;
                }
                return true;
            }
            //--是否包含某个任务的某个分片信息。
            ,hasChunk:function(fileMD5,chunkSequence){
                if(this.hasTask(fileMD5)==false){
                    return false;
                }
                if(_taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence]==undefined){
                    return false;
                }
                return true;
            }
            ,getChunk:function(fileMD5,chunkSequence){
                if(this.hasTask(fileMD5)==false){
                    return null;
                }
                if(_taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence]==undefined){
                    return null;
                }
                return _taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence];

            }
            //--删除任务。
            ,delTask:function(fileMD5){
                if(this.hasTask(fileMD5)){
                delete _taskQueue["md5_"+fileMD5];
                return true;
                }
                else{
                    return false;
                }
            }
            //--删除某个分片的信息。
            //--该方法禁用!!!本地需要这一份记录
            ,delChunk:function(fileMD5,chunkSequence){
                if(this.hasChunk(fileMD5,chunkSequence)){
                    delete _taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence];
                    //--计算是否还有分片,假如没有的话,那么就删除这个任务算了。
                    var chunksTotal=0;
                    for(var key in _taskQueue["md5_"+fileMD5]){
                        if(key.indexOf('chunk_')!=-1){
                            chunksTotal++;
                            break;
                        }
                    }
                    if(chunksTotal<=0){
                        this.delTask(fileMD5);
                    }
                    return true;
                }
                return false;
            }
            //--还剩下多少个任务。
            ,getTaskCount:function(){
                var _count=0;
                for(var key in _taskQueue){
                    if(key.indexOf("md5_")!=-1){
                        _count++;
                    }
                }
                return _count;
            }
            //--设置任务状态。
            ,setStatus:function(status){
                this.status=status;
            }
            //--获取任务状态。
            ,getStatus:function(){
                return this.status;
            }
            //--获取第一个任务切片
            /**
             * 值得注意的是,第一个任务列表必然是内存文件的第一个文件的列表第一块。。。。
             * */
            ,getFirstChunkTask:function(){
                var _task="";

                if(_fileUploadInfo.files.length<=0){
                    return null;
                }
                var _theMD5=_fileUploadInfo.files[0].md5;
                if(_taskQueue["md5_"+_theMD5]==undefined||_taskQueue["md5_"+_theMD5]["chunk_0"]==undefined){
                    return null;
                }
                return _taskQueue["md5_"+_theMD5]["chunk_0"];
            }
            //--获取下一个任务切片
            ,getNextChunkTask:function(fileMD5,chunkSequence){
                if(_fileUploadInfo.files.length<=0){
                    return null;
                }
                var _task="";
                var c2=this.getChunk(fileMD5,chunkSequence+1);
                if(c2!=null){
                    return c2;
                }
                //--假如c2是null,那么需要看下一片的位置。
                var _nowFileIndex=-1;
                var _cindex=-1;
                //--从内存文件里面获取下一个文件的md5.
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    var item=_fileUploadInfo.files[i];
                    if(fileMD5==item.md5){
                        _nowFileIndex=i;
                        break;
                    }
                }
                if(_nowFileIndex<0){
                    return this.getFirstChunkTask();
                }
                if(_nowFileIndex<0||(_nowFileIndex+1)>=_fileUploadInfo.files.length){
                    return null;
                }
                var _nextFileMD5=_fileUploadInfo.files[(_nowFileIndex+1)].md5;
                if(_taskQueue["md5_"+_nextFileMD5]==undefined||_taskQueue["md5_"+_nextFileMD5]["chunk_0"]==undefined){
                    return null;
                }
                return _taskQueue["md5_"+_nextFileMD5]["chunk_0"];
            }
            //--获取当前任务文件的下一个任务切片
            ,getNextFileFirstChunkTask:function(fileMD5){
                var _task="";
                if(_fileUploadInfo.files.length<=0){
                    return null;
                }
                //--假如c2是null,那么需要看下一片的位置。
                var _nowFileIndex=-1;
                var _cindex=-1;
                //--从内存文件里面获取下一个文件的md5.
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    var item=_fileUploadInfo.files[i];
                    if(fileMD5==item.md5){
                        _nowFileIndex=i;
                        break;
                    }
                }
                if(_nowFileIndex<0||(_nowFileIndex+1)>=_fileUploadInfo.files.length){
                    return null;
                }
                var _nextFileMD5=_fileUploadInfo.files[(_nowFileIndex+1)].md5;
                if(_taskQueue["md5_"+_nextFileMD5]==undefined||_taskQueue["md5_"+_nextFileMD5]["chunk_0"]==undefined){
                    return null;
                }
                return _taskQueue["md5_"+_nextFileMD5]["chunk_0"];
            }

        };



        //--存储管理器
        var storageManager={
            //--初始化方法,将storage里面的信息读取出来初始化为内存里面的_fileUploadInfo及_memoryFiles
            init:function(){
                var jsonstr=localStorage.getItem(defaults.storageKey);
                if(jsonstr==undefined||jsonstr==null||util.checkEmpty(jsonstr)==true){
                    return;
                }
                _fileUploadInfo= JSON.parse(jsonstr);
                //--顺便初始化内存里面的Files。
                _memoryFiles=[];
                if(_fileUploadInfo.uploaded==undefined){
                    _fileUploadInfo.uploaded=[];
                }
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    var _newFile= $.extend({},_fileUploadInfo.files[i]);
                    _memoryFiles.push(_newFile);
                }

            }
            //--将内存里面的文件上传信息重新保存到storage下面
            ,save:function(){
                //--将_fileUploadInfo字符串化,保存到浏览器里面
                var jsonstr= JSON.stringify(_fileUploadInfo);
                localStorage.setItem(defaults.storageKey,jsonstr);
            }
            //--在上面使用了方法uploader的caculateFileInfo获得了相关信息以后,那么就需要将它添加或者更新到现有的内容数据里面去了(这部分只是更新数据,不包含持久化到storage里面,请自行调用storageManager.save()方法)
            ,updateMemoryFileList:function(resultFileInfo){
                //--检查一下_memoryFiles有没有。
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==resultFileInfo.md5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                if(_mfile==null){
                    _mfile=resultFileInfo;
                    _mfile.percent=0;
                    _memoryFiles.push(_mfile);
                }
                else{
                    var _theOriginFile=_mfile.file;
                    delete _mfile.file;
                    var _theResFile=resultFileInfo.file;
                    delete resultFileInfo.file;
                    if(_mfile.percent==undefined){
                        _mfile.percent=0;
                    }
                    delete resultFileInfo.percent;
                    _mfile= $.extend(_mfile,resultFileInfo);
                    resultFileInfo.file=_theResFile;
                    _mfile.file=_theResFile;
                }

                //同步检查内存的文件列表映射。
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==resultFileInfo.md5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile==null){
                    var _theresFile=resultFileInfo.file;
                    delete resultFileInfo.file;
                    resultFileInfo.percent=0;
                    var _newobj= $.extend({},resultFileInfo);
                    _newobj.percent=0;
                    _fileUploadInfo.files.push(_newobj);
                    resultFileInfo.file=_theresFile;
                }
                else{
                    var _theresFile=resultFileInfo.file;
                    delete resultFileInfo.file;
                    if(_tfile.percent==undefined){
                        _tfile.percent=0;
                    }
                    delete resultFileInfo.percent;

                    var _tfile= $.extend({},_tfile,resultFileInfo);
                    resultFileInfo.file=_theresFile;
                }
            }
            //--这部分是删除对应的md5内存文件信息,请注意,它不包含持久化到storage,请自行调用storageManager.save
            ,deleteMemoryFile:function(fileMD5){
                //--检查一下_memoryFiles有没有。
                var _mfile_index=-1;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==fileMD5){
                        _mfile_index=i;
                        break;
                    }
                }

                //同步检查内存的文件列表映射。
                var _tfile_index=-1;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile_index=i;
                        break;
                    }
                }
                if(_mfile_index!=-1){
                    _memoryFiles.splice(_mfile_index,1);
                }
                if(_tfile_index!=-1){
                    _fileUploadInfo.files.splice(_tfile_index,1);
                }
            }
            //--将上传的进度保存到内存里面,请注意,这个也是没有自动更新到storage里面的,请自行调用save方法。
            ,updateFileProcess:function(fileMD5,uploadedChunks,percent){
                //--检查一下_memoryFiles有没有。
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==fileMD5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                if(_mfile!=null){
                    _mfile.uploadedChunks=uploadedChunks;
                    _mfile.percent=percent;
                }
                //同步检查内存的文件列表映射。
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile!=null){

                    _tfile.uploadedChunks=uploadedChunks;
                    _tfile.percent=percent;
                }
            }
            //--将上传的信息的状态保存到内存里面,请注意,这个也是没有自动更新到storage里面的,请自行调用save方法。
            ,updateFileStatus:function(fileMD5,status){
                //--检查一下_memoryFiles有没有。
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==fileMD5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                if(_mfile!=null){
                    _mfile.uploadstatus=status;

                }
                //同步检查内存的文件列表映射。
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile!=null){
                    _tfile.uploadstatus=status;
                }
            }
            //--判断该文件是否包含在内存文件里面
           ,hasFileInMemory:function(fileMD5){
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==fileMD5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                if(_mfile==null){
                    return false;
                }
                else{
                    return true;
                }
            }
            //--获取某个momery 里面的 文件信息。
            ,getMemoryFile:function(fileMD5){
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==fileMD5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                return _mfile;
            }
            ,getFileInfo:function(fileMD5){
                //同步检查内存的文件列表映射。
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                return _tfile;
            }
           //--判断当前文件已经上传的块是否包含这个。。
            //--返回格式:{hasFile:是否有这个文件,status:是否已经上传了}
            ,isChunkUploaded:function(fileMD5,chunkSequence){
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile!=null){
                    var _has=false;
                    if(_tfile.uploaded!=undefined&&_tfile.uploaded.length>0){
                        for(var i=0;i<_tfile.uploaded.length;i++){
                            var _chunkseq=_tfile.uploaded[i];
                            if(_chunkseq==chunkSequence){
                                _has=true;
                                break;
                            }
                        }
                    }
                    return {
                        hasFile:true,
                        status:_has
                    };
                }
                else{
                    return {
                        hasFile:false,
                        status:false
                    };
                }
            }
            //--添加一个上传块。
            //--返回信息:{hasFile:是否有这个文件,hasChunk:是否已经有这一块了,status:是否添加成功}
            ,addUploadedChunk:function(fileMD5,chunkSequence){
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile!=null){
                    var _has=false;
                    if(_tfile.uploaded!=undefined&&_tfile.uploaded.length>0){
                        for(var i=0;i<_tfile.uploaded.length;i++){
                            var _chunkseq=_tfile.uploaded[i];
                            if(_chunkseq==chunkSequence){
                                _has=true;
                                break;
                            }
                        }

                        if(_has){
                            return {
                                hasFile:true,
                                hasChunk:true,
                                status:false
                            };
                        }
                        else{
                            _tfile.uploaded.push(chunkSequence);
                            return {
                                hasFile:true,
                                hasChunk:false,
                                status:true
                            };
                        }
                    }
                    else{
                        _tfile.uploaded.push(chunkSequence);
                        return {
                            hasFile:true,
                            hasChunk:false,
                            status:true
                        };
                    }
                }
                else{
                    return {
                        hasFile:false,
                        hasChunk:false,
                        status:false
                    };
                }
            }
            //--删除某个文件的已经上传了的分块的信息。
            //--返回信息:{hasFile:是否有这个文件,hasChunk:是否已经有这一块了,status:是否删除成功}
            ,delUploadedChunk:function(fileMD5,chunkSequence){
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==fileMD5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile!=null){
                    var _has=false;
                    var _chunkIndex=-1;
                    if(_tfile.uploaded!=undefined&&_tfile.uploaded.length>0){
                        for(var i=0;i<_tfile.uploaded.length;i++){
                            var _chunkseq=_tfile.uploaded[i];
                            if(_chunkseq==chunkSequence){
                                _has=true;
                                _chunkIndex=i;
                                break;
                            }
                        }

                        if(_has){
                            _tfile.uploaded.splice(_chunkIndex,1);
                            return {
                                hasFile:true,
                                hasChunk:true,
                                status:true
                            };
                        }
                        else{
                            return {
                                hasFile:true,
                                hasChunk:false,
                                status:false
                            };
                        }
                    }
                    else{

                        return {
                            hasFile:false,
                            hasChunk:false,
                            status:false
                        };
                    }
                }
                else{
                    return {
                        hasFile:false,
                        hasChunk:false,
                        status:false
                    };
                }
            }


            //--该方法判断是否包含这个块。

            //--该方法删除某个块序号。请注意,没有自动更新到storage,请自行调用save方法。

        };

        //--定时任务管理器

        var timerManager={
            interval:null
            ,canRun:false //外部用的接口,只有在canRun为true,busy为false的时候才能运行下一个任务。
            ,busy:false //内部是否有任务正在运行,有正在运行的任务就必须等待该任务,无论canRun是否为true。
            ,sleep:function(){
                this.canRun=false;
            }
            ,wake:function(){
                this.canRun=true;
            }
            ,setBusy:function(bool_busy){
                this.busy=bool_busy;
            }
            ,isBusy:function(){
                return this.busy;
            }
            ,init:function(opts){
                if(this.interval!=null){
                    //--
                    //请先清除定时器
                    return;
                }
                var defaultsLV2={
                    speed:10
                    ,runnable:function(){

                    }
                    ,runRightNow:false
                };
                defaultsLV2=$.extend({},defaultsLV2,opts);
                var _that=this;

                this.interval=setInterval(function(){
                if(_that.canRun&&_that.busy==false){
                    defaultsLV2.runnable();
                }
                    else{

                }
                },defaultsLV2.speed);
                this.canRun=defaultsLV2.runRightNow;


            }
        };

        //-----界面控制器
        //--按钮控制界面。
        var uploadButtonUI={
            //--初始化界面及将外界的事件作为响应时间
            init:function(options){
                var defaultsLV2={
                    onFileSelected:function(originFiles){} //回调函数,表示当用户选择了一个或多个文件以后执行的方法。
                };
                defaultsLV2= $.extend({},defaultsLV2,options);
                var html= F.renderButtonTPL();
                _that.html(html);
                //--添加响应事件
                $('#'+defaults.fileBrowserButtonId).on('click',function(){
                    $('#'+defaults.fileInputId).trigger('click');
                });
                document.getElementById(defaults.fileInputId).addEventListener("change", function() {
                    var files = document.getElementById(defaults.fileInputId).files;
                    files= F._filter(files);
                    defaultsLV2.onFileSelected(files);
                });
            }

        };
        //--列表控制界面。
        var uploadListUI={
            //--初始化列表
            init:function(opts){
                var defaultLV2={
                    onUploadClick:function(fileMD5){

                    }//点击上传按钮后的事件,注意,参数只有一个md5码,请自行通过这个码获取相关文件句柄。
                    ,onDelClick:function(fileMD5){

                    }//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
                };//设置
                defaultLV2= $.extend({},defaultLV2,opts);
                var html=_tpl_list.render({
                    F:F,
                    items:_memoryFiles
                });
                $("#"+defaults.queuePanelId).html(html);
                //--初始化事件。
                $("#"+defaults.queuePanelId).find(".uploadbtn").click(function(){
                    var _md5=$(this).attr("_md5");
                    defaultLV2.onUploadClick(_md5);
                });
                $("#"+defaults.queuePanelId).find(".delfilebtn").click(function(){
                    var _md5=$(this).attr("_md5");
                    defaultLV2.onDelClick(_md5);
                });

            },
            //--添加新的
            addFile:function(theFileInfo,opts){
                var defaultLV2={
                    onUploadClick:function(fileMD5){

                    }//点击上传按钮后的事件,注意,参数只有一个md5码,请自行通过这个码获取相关文件句柄。
                    ,onDelClick:function(fileMD5){

                    }//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
                };//设置
                defaultLV2= $.extend({},defaultLV2,opts);

                var _arr=[];
                _arr.push(theFileInfo);
                var html=_tpl_list.render({
                    F:F,
                    items:_arr
                });
                var el=$(html);
                $("#"+defaults.queuePanelId).append(el);
                //--初始化事件。
                $(el).find(".uploadbtn").click(function(){
                    var _md5=$(this).attr("_md5");
                    defaultLV2.onUploadClick(_md5);
                });
                $(el).find(".delfilebtn").click(function(){
                    var _md5=$(this).attr("_md5");
                    defaultLV2.onDelClick(_md5);
                });
            },
            //--更新ui
            editFile:function(theFileInfo){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+theFileInfo.md5+"']");
                if(el.length<=0){
                    return;
                }
                var ui_fileName=$(el).find(".up_filename");
                var ui_totalsize=$(el).find(".totalsize");
                var ui_up_percent=$(el).find(".up_percent");
                var ui_process=$(el).find(".uploadify-progress-bar");

                ui_fileName.text(theFileInfo.fileName);
                ui_totalsize.text(F.formatFileSize(theFileInfo.fileSize));
                ui_up_percent.text(theFileInfo.percent+"%");
                ui_process.css("width",theFileInfo.percent+"%");

            },
            //--判断是否有这个列表item。
            hasFileItem:function(fileMD5){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return false;
                }
                return true;
            },
            //--通过md5,更新当前进度。
            updatePercent:function(fileMD5,percent){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return;
                }
                var ui_up_percent=$(el).find(".up_percent");
                var ui_process=$(el).find(".uploadify-progress-bar");
                ui_up_percent.text(percent+"%");
                ui_process.css("width",percent+"%");
            },
            //设置当前uiitem为上传中的状态。
            setStatus_Uploading:function(fileMD5){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return;
                }
                var ui_Btn=$(el).find(".delfilebtn");
                var ui_uploadBtn=$(el).find(".uploadbtn");
                var ui_uploadStatus=$(el).find(".upload_status");
                ui_uploadStatus.text("正在上传");
                ui_uploadBtn.text("上传中");
                ui_uploadBtn.attr("disabled","disabled");
                ui_Btn.attr("disabled","disabled");

            },
            //设置当前某个ui的状态为准备上传
            setStatus_Ready:function(fileMD5){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return;
                }
                var ui_Btn=$(el).find(".delfilebtn");
                var ui_uploadBtn=$(el).find(".uploadbtn");
                var ui_uploadStatus=$(el).find(".upload_status");
                ui_uploadStatus.text("文件就绪");
                ui_uploadBtn.text("上传");
                ui_uploadBtn.removeAttr("disabled");
                ui_Btn.css("display","inline-block");
                ui_Btn.removeAttr("disabled");
                ui_uploadBtn.css("display","inline-block");
            },
            hideFile:function(fileMD5,opts){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return;
                }
                var defaultsLV3={
                    speed:500,
                    callback:function(){}
                };
                defaultsLV3= $.extend({},defaultsLV3,opts);
                el.slideUp(defaultsLV3.speed,function(){
                    defaultsLV3.callback();
                });
            },
            //--更新界面,设置删除按钮是否可用。
            enableDelButton:function(fileMD5,enabled){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return;
                }
                var ui_Btn=$(el).find(".delfilebtn");
                if(enabled){
                    ui_Btn.removeAttr("disabled");

                }
                else{
                    ui_Btn.attr("disabled","disabled");
                }
            },
            //--删除某个文件的列表ui
            delFile:function(fileMD5){
                var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
                if(el.length<=0){
                    return;
                }
                el.remove();
            }
        };
        //--上传控制器。
        var uploadManager={
            //--当前上传的分块。
            currentUpload:{
                md5:null,
                chunkSequence:0
            },
            nextUpload:{
                md5:undefined,
                chunkSequence:undefined
            },
            //--计算及完成某个文件的相关信息。譬如,md5,分块,文件名称等等。这也是异步的。>_<
            caculateFileInfo:function(originFile,opts){
                var defaultsLV2={
                    onFinished:function(theResultFileInfo){

                    }//计算完毕以后,会调用这个方法。
                };
                defaultsLV2= $.extend({},defaultsLV2,opts);
                var _freder=new FileReader();
                _freder.onload = function(e) {
                    var __resultInfo={
                        md5:"" //md5码
                        ,fileName:"" //文件名称
                        ,fileSize:0 //文件大小
                        ,fileType:""
                        ,lastModified:"2014-01-01" //最近修改日期
                        ,chunks:0 //文件分块数量
                        ,uploadstatus:FileUploadStatus.ready //文件上传状态。
                        ,file:null //文件句柄
                        ,percent:0
                        ,uploadedChunks:0 //已经上传了的分片数量
                        ,uploaded:[] //文件已经上传了的分块序号列表
                    };
                    var  sparkMd5_partial=new SparkMD5();
                    sparkMd5_partial.appendBinary(e.target.result);
                    var partialMd5= sparkMd5_partial.end();
                    __resultInfo.md5=partialMd5;
                    __resultInfo.fileName=originFile.name;
                    __resultInfo.fileSize=originFile.size;
                    __resultInfo.fileType=originFile.type;
                    __resultInfo.file=originFile;
                    __resultInfo.lastModified=originFile.lastModified;
                    //--计算分块。
                    var _realKBs=Math.ceil(__resultInfo.fileSize/1024);
                    var chunks = Math.ceil(__resultInfo.fileSize /defaults.fileSplitSize);
                    __resultInfo.chunks=chunks;
                    //--调用回调函数。
                    defaultsLV2.onFinished(__resultInfo);
                };
                _freder.readAsBinaryString(originFile);
            },
            //--在上面使用了方法uploader的caculateFileInfo获得了相关信息以后,那么就需要将它添加或者更新到现有的内容数据里面去了(这部分只是更新数据,不包含持久化到storage里面,请自行调用storageManager.save()方法)
            updateMemoryFileList:function(resultFileInfo){
                //--检查一下_memoryFiles有没有。
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==resultFileInfo.md5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                if(_mfile==null){
                    _mfile=resultFileInfo;
                    _memoryFiles.push(_mfile);
                }
                else{
                    var _theOriginFile=_mfile.file;
                    delete _mfile.file;
                    var _theResFile=resultFileInfo.file;
                    delete resultFileInfo.file;
                    _mfile= $.extend(_mfile,resultFileInfo);
                    resultFileInfo.file=_theResFile;
                    _mfile=_theResFile;
                }
                //同步检查内存的文件列表映射。
                var _tfile=null;
                for(var i=0;i<_fileUploadInfo.files.length;i++){
                    if(_fileUploadInfo.files[i].md5==resultFileInfo.md5){
                        _tfile=_fileUploadInfo.files[i];
                        break;
                    }
                }
                if(_tfile==null){
                    var _theresFile=resultFileInfo.file;
                    delete resultFileInfo.file;
                    var _newobj= $.extend({},resultFileInfo);
                    _fileUploadInfo.files.push(_newobj);
                    resultFileInfo.file=_theresFile;
                }
                else{
                    var _theresFile=resultFileInfo.file;
                    delete resultFileInfo.file;
                    var _tfile= $.extend({},_tfile,resultFileInfo);
                    resultFileInfo.file=_theresFile;
                }
            },
            //--获取当前文件的信息以后,那么就需要处理一下这些信息,变成任务队列的任务信息了。
            setTask:function(TheResultInfo){
                var _md5=TheResultInfo.md5;
                if(_md5==undefined||_md5==null){
                    return;
                }
                //--判断内存里面有没有这份文件。
                var res=storageManager.hasFileInMemory(_md5);
                if(res==false){
                    return;
                }
                //--那么计算分片了。
                for(var i=0;i<TheResultInfo.chunks;i++){
                    var _begin=0;
                    var _end=0;
                    var start = i * defaults.fileSplitSize;
                    var end = start + defaults.fileSplitSize >= TheResultInfo.fileSize ? TheResultInfo.fileSize : start + defaults.fileSplitSize;
                    taskQueueManager.addTask(TheResultInfo.md5,i,start,end);
                }
            },
            //--上传单个文件。
            uploadFile:function(fileMD5,opts){
                var defaultsLV2={
                    beforeUpload:function(fileInfo){}
                };

                defaultsLV2= $.extend({},defaultsLV2,opts);
                //--从memory文件列表中看看有没有这份文件信息,并且,这份文件信息的file不能为空。
                var _mfile=null;
                for(var i=0;i<_memoryFiles.length;i++){
                    if(_memoryFiles[i].md5==fileMD5){
                        _mfile=_memoryFiles[i];
                        break;
                    }
                }
                if(_mfile==null||_mfile.file==undefined||_mfile.file==null){
                    return;
                }
                //--方法内通用的变量。
                var xhr = null;//请求。
                var originalFile = _mfile.file;//保存原始未切割的文件引用

                try{
                    xhr=new XMLHttpRequest();
                }catch(e){
                    xhr=ActiveXobject("Msxml12.XMLHTTP");
                }


                    file = originalFile.slice(uploadedSize,uploadedSize + option.fileSplitSize);
                    file.status = originalFile.status;
                    file.name = originalFile.name;

                if(xhr.upload){
                    // 上传中
                    xhr.upload.onprogress = function(e) {
                        uploadManager.onProgress(file, originalFile, e.loaded, e.total);
                    };

                    xhr.onreadystatechange = function(e) {
                        if(xhr.readyState == 4){
                            uploadManager.uploadOver = true;
                            if(xhr.status == 200){
                                if(option.breakPoints){
                                    //保存已上传文件大小
                                    uploadedSize += option.fileSplitSize;
                                    if(option.saveUploadedSize){
                                        option.saveUploadedSize(originalFile,uploadedSize);
                                    }
                                    else{
                                        alert('请先配置saveUploadedSize参数!');
                                        return;
                                    }
                                    //继续上传其他片段
                                    if(uploadedSize<originalFile.size){
                                        uploadManager.uploadOver = false;
                                        if(!uploadManager.uploadStopped){
                                            file = originalFile.slice(uploadedSize,uploadedSize + option.fileSplitSize);
                                            file.status = originalFile.status;
                                            file.name = originalFile.name;
                                            uploadManager._sendBlob(xhr, file, originalFile);
                                        }
                                    }
                                    else{
                                        uploadManager._uploadSucessCallback(originalFile, xhr);
                                    }
                                }
                                else{
                                    uploadManager._uploadSucessCallback(originalFile, xhr);
                                }
                            }
                            else {
                                originalFile.status = 3;//标记为上传失败
                                option.onUploadError && option.onUploadError(originalFile, xhr.responseText);
                            }

                            //无论上传成功或失败均执行下面的代码
                            if(uploadManager.uploadOver){
                                option.onUploadComplete && option.onUploadComplete(originalFile,xhr.responseText);
                                //检测队列中的文件是否全部上传完成,执行onQueueComplete
                                if(option.onQueueComplete){
                                    var queueData = uploadManager._allFilesUploaded();
                                    queueData && option.onQueueComplete(queueData);
                                }

                                //清除文件选择框中的已有值
                                uploadManager._getInputBtn().val('');
                            }

                        }
                    }

                    //开始上传文件
                    option.onUploadStart && option.onUploadStart(originalFile);
                    uploadManager._sendBlob(xhr, file, originalFile);

                }


            }
            //上传文件片
            ,_sendBlob : function(xhr, file, originalfile){
                if(file.status===0){
                    file.status = 1;//标记为正在上传
                    uploadManager.uploadStopped = false;
                    xhr.open(defaults.method, defaults.uploader, true);
                    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
                    var fd = new FormData();
                    fd.append(defaults.fileObjName,file);
                    fd.append(defaults.fileObjName, originalfile.name);
                    fd.append('lastModifiedDate', originalfile.lastModifiedDate.getTime());
                    if(defaults.formData){
                        for(var key in defaults.formData){
                            fd.append(key,defaults.formData[key]);
                        }
                    }
                    xhr.send(fd);
                }
            }
            ,_chunkTask:function(xhr){
                timerManager.setBusy(true);
                var _that=this;
                if(_that.currentUpload==undefined||_that.currentUpload.md5==undefined){
                    timerManager.sleep();
                    timerManager.setBusy(false);
                    return;
                }
                var _currentChunkTaskInfo= taskQueueManager.getChunk(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
                if(_currentChunkTaskInfo==null){
                    //-没有这一块啊。。断了吧。
                    timerManager.sleep();
                    timerManager.setBusy(false);
                    return;
                }
                var _currentFileInfo=storageManager.getFileInfo(_that.currentUpload.md5);
                //--是否当前文件的第一块?
                if(_that.currentUpload.chunkSequence===0){
                    //-是,那么执行开始发送文件前的方法。
                    var _ex_fileInfo= $.extend({},_currentFileInfo);
                    defaults.onBeforeSendFile(_that.currentUpload.md5,_ex_fileInfo);
                }
                var __paras_to_send={};
                //--执行上传分片前的方法。
                defaults.onBeforeSendBlob(_that.currentUpload.md5,_that.currentUpload.chunkSequence,__paras_to_send);

                //--判断当前是否允许上传分片。
                var _cStatus=storageManager.isChunkUploaded(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
                if(_cStatus.status===true){
                    defaults.onAfterSendBlob(_that.currentUpload.md5,_that.currentUpload.chunkSequence,true);
                    //--是否是最后一片了。
                    if(_currentFileInfo.chunks-1<=_that.currentUpload.chunkSequence){
                        //--删除内存中这个文件的数据--上传完成就不需要记录了。别删除任务的上传历史记录了。。。。这是用来核对的。。//
                        taskQueueManager.delTask(_that.currentUpload.md5);

                        storageManager.deleteMemoryFile(_that.currentUpload.md5);
                        storageManager.save();
                        var _theMD5=_that.currentUpload.md5;
                        uploadListUI.hideFile(_theMD5,{
                            callback:function(){
                                uploadListUI.delFile(_theMD5);
                            }
                        });
                        //-是,那么执行开始发送文件前的方法。
                        var _ex_fileInfo= $.extend({},_currentFileInfo);
                        defaults.onAfterSendFile(_theMD5,_ex_fileInfo);
                    }
                    //--继续获取下一片。假如有下一片,那么就继续,假如没有,那么就算了。
                    var _nextChunkTask=taskQueueManager.getNextChunkTask(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
                    console.log("下一片");
                    console.log(_nextChunkTask);
                    if(_nextChunkTask==null){
                        _that.currentUpload={};
                        timerManager.sleep();
                        timerManager.setBusy(false);
                    }
                    else{
                        _that.currentUpload={
                            md5:_nextChunkTask.md5,
                            chunkSequence:_nextChunkTask.chunk
                        };
                        timerManager.setBusy(false);
                        timerManager.wake();
                    }

                }
                else{
                    //--没有上传,那么现在就来上传了。
                    _that.sendBlob(xhr,_currentChunkTaskInfo,__paras_to_send);
                }
            }
            ,sendBlob:function(xhr,chunkTaskInfo,paras){
                timerManager.setBusy(true);
                var memoryfile=storageManager.getMemoryFile(chunkTaskInfo.md5);
                var originalfile=memoryfile.file;
                //--获取任务信息并且切片。
                xhr.open(defaults.method, defaults.uploader, true);
                xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
                var fd = new FormData();

                //--切片
                var chunkInfo= chunkTaskInfo;
                var fileBlob= originalfile.slice(chunkInfo.begin,chunkInfo.end);
                fd.append(defaults.fileObjName,fileBlob);
                //fd.append(defaults.fileObjName, originalfile.name);
                fd.append('lastModifiedDate', originalfile.lastModifiedDate.getTime());

                if(defaults.formData){
                    for(var key in defaults.formData){
                        fd.append(key,defaults.formData[key]);
                    }
                }
                //--
                if(paras!=null&¶s!=undefined){
                    for(var key in paras){
                        fd.append(key,paras[key]);
                    }
                }
                xhr.send(fd);
            }
            //--开始上传任务。
            ,uploadBegin:function(){
                var _that=this;
                if(taskQueueManager.getTaskCount()<=0){
                    return;
                }
                if(timerManager.interval!=null){
                    //--重新获取第一个切片。
                    //--开始执行任务。
                    var _chunkBegin=taskQueueManager.getFirstChunkTask();
                    if(_chunkBegin!=undefined&&_chunkBegin!=null){
                        _that.currentUpload={
                            md5:_chunkBegin.md5,
                            chunkSequence:_chunkBegin.chunk
                        };
                    }
                    timerManager.setBusy(false);
                    timerManager.wake();
                    return;
                }
                taskQueueManager.setStatus("begin");
                uploadManager.currentUpload={};
                //--新建一个request
                //--方法内通用的变量。
                var xhr = null;//请求。
                try{
                    xhr=new XMLHttpRequest();
                }catch(e){
                    xhr=ActiveXobject("Msxml12.XMLHTTP");
                }

                xhr.onreadystatechange = function(e) {

                    if(xhr.readyState == 4){
                        if(xhr.status == 200){
                            //--回调的时候处理相关操作
                            //--更新已经上传的分片的数据。
                            storageManager.addUploadedChunk(_that.currentUpload.md5,_that.currentUpload.chunkSequence);

                            //--更新界面。
                            var _currentFileInfo=storageManager.getFileInfo(_that.currentUpload.md5);
                            var __percent=_currentFileInfo.chunks<=0?100:parseInt(_currentFileInfo.uploaded.length*100/_currentFileInfo.chunks);
                            storageManager.updateFileProcess(_that.currentUpload.md5,_currentFileInfo.uploaded.length,__percent);
                            storageManager.save();
                            uploadListUI.updatePercent(_that.currentUpload.md5,__percent);
                            //--是否已经结束了。
                            defaults.onAfterSendBlob(_that.currentUpload.md5,_that.currentUpload.chunkSequence,false);
                            //--是否是最后一片了。
                            if(_currentFileInfo.chunks-1<=_that.currentUpload.chunkSequence){
                                //--删除内存中这个文件的数据--上传完成就不需要记录了。别删除任务的上传历史记录了。。。。这是用来核对的。。//
                                taskQueueManager.delTask(_that.currentUpload.md5);
                                storageManager.deleteMemoryFile(_that.currentUpload.md5);
                                storageManager.save();
                                var _theMD5=_that.currentUpload.md5;
                                uploadListUI.hideFile(_theMD5,{
                                    callback:function(){
                                        uploadListUI.delFile(_theMD5);
                                    }
                                });
                                //-是,那么执行开始发送文件前的方法。
                                var _ex_fileInfo= $.extend({},_currentFileInfo);
                                defaults.onAfterSendFile(_theMD5,_ex_fileInfo);
                            }
                            //--还有没有下一片?
                            //--删除任务队列相关信息。

                            //--继续获取下一片。假如有下一片,那么就继续,假如没有,那么就算了。
                            var _nextChunkTask=taskQueueManager.getNextChunkTask(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
                            console.log("下一片");
                            console.log(_nextChunkTask);
                            if(_nextChunkTask==null){
                                _that.currentUpload={};
                                timerManager.sleep();
                                timerManager.setBusy(false);
                            }
                            else{
                                _that.currentUpload={
                                    md5:_nextChunkTask.md5,
                                    chunkSequence:_nextChunkTask.chunk
                                };
                                timerManager.setBusy(false);
                                timerManager.wake();
                            }

                        }
                        else {
                            alert("上传失败!");
                        }
                    }
                }
                //--开始执行任务。
                var _chunkBegin=taskQueueManager.getFirstChunkTask();
                if(_chunkBegin!=undefined&&_chunkBegin!=null){
                    _that.currentUpload={
                        md5:_chunkBegin.md5,
                        chunkSequence:_chunkBegin.chunk
                    };
                }
                timerManager.init({
                    speed:10,
                    runnable:function(){
                        _that._chunkTask(xhr);
                    },
                    runRightNow:true
                });

            }
        };
        //--app总控制器。。将各个小部件都调用组织起来。
        var app={
            //--入口函数,初始化整个app。
            init:function(){
                //--获取本地上传数据并保存到内存中。
                storageManager.init();
                //--初始化上传按钮。
                uploadButtonUI.init({
                    onFileSelected:function(originFiles){
                        //选择完文件,获得有效文件列表后,获得当前文件的列表信息。并且添加到列表ui里面去。
                        for(var i=0;i<originFiles.length;i++){
                            var _file=originFiles[i];
                            uploadManager.caculateFileInfo(_file,{
                                onFinished:function(theResultFileInfo){

                                    storageManager.updateMemoryFileList(theResultFileInfo);
                                    //--同步到本地存储。
                                    storageManager.save();
                                    //--更新到任务列表,随时准备上传。
                                    uploadManager.setTask(theResultFileInfo);

                                    //--更新到列表界面。
                                    var _newFileInfo=storageManager.getMemoryFile(theResultFileInfo.md5);
                                    if(uploadListUI.hasFileItem(theResultFileInfo.md5)){
                                        uploadListUI.editFile(_newFileInfo);
                                        uploadListUI.setStatus_Ready(theResultFileInfo.md5);
                                    }
                                    else{
                                        uploadListUI.addFile(_newFileInfo,{
                                           onDelClick:function(fileMD5){
                                                app.deleteFile(fileMD5);
                                            }//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
                                        });
                                        uploadListUI.setStatus_Ready(theResultFileInfo.md5);
                                    }
                                }
                            });
                        }
                    }
                });
                //--初始化列表ui
                uploadListUI.init({
                   onDelClick:function(fileMD5){
                        app.deleteFile(fileMD5);
                    }//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
                });
            }
            //--删除某个文件(以md5作为标志)的处理方式。
            ,deleteFile:function(fileMD5){
                storageManager.deleteMemoryFile(fileMD5);
                storageManager.save();
                //--删除内存中这个文件的数据--上传完成就不需要记录了。别删除任务的上传历史记录了。。。。这是用来核对的。。//
                if(_that.currentUpload!=undefined&&_that.currentUpload.md5!=undefined){
                    taskQueueManager.delTask(_that.currentUpload.md5);
                }
                uploadListUI.delFile(fileMD5);
            }
        };




        //--初始化及开始运行app
        app.init();

        //--对外接口。
        //--开始上传选定的文件及列表。
        var returnObj={
            upload:function(){
                uploadManager.uploadBegin();
            }
            ,sleep:function(){
                timerManager.sleep();
            }
            ,wake:function(){
                timerManager.wake();
            }
            ,debug:function(){
                console.log("_fileUploadInfo");
                console.log(_fileUploadInfo);
                console.log("_memoryfileInfo");
                console.log(_memoryFiles);
                console.log("_task");
                console.log(_taskQueue);
                console.log(timerManager);
            }
        };
        return returnObj;
    }
})(jQuery)


服务端代码


处理分片的保存

<%@ page import="java.util.Hashtable" %>
<%@ page import="java.io.File" %>
<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="org.apache.commons.fileupload.FileItem" %>
<%@ page import="com.alibaba.fastjson.JSON" %>
<%@ page import="java.util.Date" %>
<%@ page import="org.apache.commons.fileupload.FileUploadException" %>
<%@ page import="Easis.Common.StringUtil" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
    /**
     * 在servlet或者jsp里面获取当前web的根目录绝对路径譬如:F:/projects/myCMS/这种形式。
     * */
    public static String getRealPath(HttpServletRequest request,String path){
        String servletPath = request.getServletPath();
        String realPath = request.getSession().getServletContext()
                .getRealPath(servletPath);
        String WebRootPath=realPath.replace('\\','/');
        WebRootPath=WebRootPath.substring(0,WebRootPath.lastIndexOf(servletPath));
        WebRootPath=(WebRootPath+"/"+path).replaceAll("//","/").replace('/','\\');
        return      WebRootPath;
    }%>
<%
    Hashtable<String,Object> _hash=new Hashtable<String, Object>(3);

    String savePath = "C:/file_tmp/";
    File f_d=new File(savePath);
    if(!f_d.exists()){
        f_d.mkdirs();
    }
    //--参数。
    String fileMD5="";
    int currentChunk=0;


    //--接收图片
    //--接收图片开始
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    upload.setHeaderEncoding("utf-8");

    try {
        List items = upload.parseRequest(request);
        Iterator itr = items.iterator();
        FileItem _fileItem=null;
        while (itr.hasNext()) {
            FileItem item = (FileItem) itr.next();
            if (item.isFormField()) {
                System.out.println("表单参数名:" + item.getFieldName() + ",表单参数值:" + item.getString("UTF-8"));
                if(item.getFieldName().equals("md5")){
                    fileMD5=item.getString("UTF-8");
                }
                else if(item.getFieldName().equals("chunks_seq")){
                    currentChunk= StringUtil.toInt(item.getString("UTF-8"));
                }
            } else {
                if (item.getName() != null && !item.getName().equals("")) {

                    _fileItem=item;
                }else{
                }
            }
        }
        if(_fileItem==null){
            _hash.put("status",false);
            _hash.put("message","没有上传任何文件!");
            _hash.put("url","");
            out.write(JSON.toJSONString(_hash));
            return;
        }
        String fileNameExt=_fileItem.getName().trim();// new String(_fileItem.getName().getBytes("gbk")).trim();
        fileNameExt=fileNameExt.substring(fileNameExt.lastIndexOf('.')+1);
        System.out.println(fileNameExt);
        String fileName_2=request.getSession().getId()+((new Date()).getTime());
        String _newFileName=fileName_2+"."+fileNameExt;
        String realFilePath=savePath+File.separator+_newFileName;
        //String realURL=_avatarRoot+"/"+_newFileName;
        //--生成分片文件。
        String _fileName=fileMD5+"_"+currentChunk+".chunk";
        realFilePath=savePath+_fileName;

        //--写入文件
        File f1=new File(realFilePath);
        if(f1.exists()){
            f1.delete();
        }
        _fileItem.write(f1);
        _hash.put("status",true);
        _hash.put("message","成功写入分块文件!");
        _hash.put("url","");
        out.write(JSON.toJSONString(_hash));
    }catch(FileUploadException e){

        e.printStackTrace();
        _hash.put("status",false);
        _hash.put("message","上传文件失败,文件流异常!");
        _hash.put("url","");
        out.write(JSON.toJSONString(_hash));
        return;
    } catch (Exception e) {
        e.printStackTrace();
        _hash.put("status",false);
        _hash.put("message","服务器500错误!");
        _hash.put("url","");
        out.write(JSON.toJSONString(_hash));
        return;
    }
    //--接收图片结束
%>


处理文件的合并

<%@ page import="java.util.Hashtable" %>
<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="org.apache.commons.fileupload.FileItem" %>
<%@ page import="com.alibaba.fastjson.JSON" %>
<%@ page import="java.util.Date" %>
<%@ page import="org.apache.commons.fileupload.FileUploadException" %>
<%@ page import="Easis.Common.StringUtil" %>
<%@ page import="Easis.HTTP.RequestEX" %>
<%@ page import="java.io.*" %>
<%--
该文件为demo文件,切勿用于实际效果,该jsp作用:
结束某个文件的分块上传时候,需要合并所有分块成为一个文件。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
    /**
     * 在servlet或者jsp里面获取当前web的根目录绝对路径譬如:F:/projects/myCMS/这种形式。
     * */
    public static String getRealPath(HttpServletRequest request,String path){
        String servletPath = request.getServletPath();
        String realPath = request.getSession().getServletContext()
                .getRealPath(servletPath);
        String WebRootPath=realPath.replace('\\','/');
        WebRootPath=WebRootPath.substring(0,WebRootPath.lastIndexOf(servletPath));
        WebRootPath=(WebRootPath+"/"+path).replaceAll("//","/").replace('/','\\');
        return      WebRootPath;
    }%>
<%
    Hashtable<String,Object> _hash=new Hashtable<String, Object>(3);

    String savePath = "C:/file_tmp/";
    String realFilePath="C:/file_real/";
    File f_d=new File(savePath);
    File f_r=new File(realFilePath);
    if(!f_d.exists()){
        f_d.mkdirs();
    }
    if(!f_r.exists()){
        f_r.mkdirs();
    }
    //--参数
    String fileMD5="";
    int totalChunks=0;
    String fileName="";

    //--接收图片
    //--接收图片开始

    RequestEX req=new RequestEX(request);
    fileMD5=req.getParaValueByBoth("md5");
    totalChunks=StringUtil.toInt(req.getParaValueByBoth("total"));
    fileName=req.getParaValueByBoth("name");

    if(StringUtil.isNullOrEmpty(fileMD5)||totalChunks<=0||StringUtil.isNullOrEmpty(fileName)){
        _hash.put("status",false);
        _hash.put("message","无法合并任何文件,缺乏必要参数!");
        _hash.put("url","");
        out.write(JSON.toJSONString(_hash));
        return;
    }

    try {

        String fileRealPath=realFilePath+fileName;
        File file_now=new File(fileRealPath);
        if(file_now.exists()){
            file_now.delete();
        }
        file_now.createNewFile();
        //--
        for(int i=0;i<totalChunks;i++){
            File f_tmp=new File(savePath+""+fileMD5+"_"+i+".chunk");
            if(f_tmp.exists()==false){
                System.out.println("无法找到:"+fileMD5+"_"+i+".chunk!!");
                continue;
            }

            long len = f_tmp.length();
            byte[] bytes = new byte[(int) len];
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(f_tmp));
            int r = bufferedInputStream.read(bytes);
            if (r != len) throw new IOException("读取文件不正确");
            bufferedInputStream.close();
            //--追加写入同样的文件。
            BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file_now,true));
            bos.write(bytes);
            //BufferedWriter out =new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f_1, true)));
            bos.close();
        }
        //_fileItem.write(f1);
        _hash.put("status",true);
        _hash.put("message","成功上传图片!");
        _hash.put("url","");
        out.write(JSON.toJSONString(_hash));
    }catch (Exception e) {
        e.printStackTrace();
        _hash.put("status",false);
        _hash.put("message","服务器500错误!");
        _hash.put("url","");
        out.write(JSON.toJSONString(_hash));
        return;
    }
    //--接收图片结束
%>


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值