欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.NetCore+WebUploader实现大文件分片上传

程序员文章站 2022-05-06 21:51:28
项目要求通过网站上传大文件,比如视频文件,通过摸索实现了文件分片来上传,然后后台进行合并。 使用了开源的前台上传插件WebUploader(http://fex.baidu.com/webuploader/) WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5 ......

项目要求通过网站上传大文件,比如视频文件,通过摸索实现了文件分片来上传,然后后台进行合并。

使用了开源的前台上传插件webuploader(http://fex.baidu.com/webuploader/)

webuploader是由baidu webfe(fex)团队开发的一个简单的以html5为主,flash为辅的现代文件上传组件。在现代的浏览器里面能充分发挥html5的优势,同时又不摒弃主流ie浏览器,沿用原来的flash运行时,兼容ie6+,ios 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。

采用大文件分片并发上传,极大的提高了文件上传效率。

 

直接上代码,前台cshtml

@{
    layout = null;
}
<!doctype html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link href="~/js/webuploader/webuploader.css" rel="stylesheet" />
    <link href="~/js/bootstrap.min.css" rel="stylesheet" />
    <script src="~/js/jquery.min.js"></script>
    <script src="~/js/webuploader/webuploader.js"></script>
    <title>upload</title>
    <script>
        jquery(function () {
            var $ = jquery,
                $list = $('#thelist'),
                $btn = $('#ctlbtn'),
                state = 'pending',
                filemd5,
                flag = true,
                datastate,
                fm = [],
                fnum,
                token,
                uploader;
            var fileext = ["mpg", "mpeg", "mp4", "avi"];
            token = '@viewbag.token';
            if (token == '' || token== 'undefined')
            {
                $("#uploader").hide();
                alert("登录超时,请重新登录。");
            }
            //监听分块上传过程中的三个时间点
            webuploader.uploader.register({
                "before-send-file": "beforesendfile",
                "before-send": "beforesend",
                "after-send-file": "aftersendfile",
            }, {
                    beforesendfile: function (file) {
                        var starttime = new date(file.lastmodifieddate);
                        filename = file.name;
                        var deferred = webuploader.deferred(); 
                        (new webuploader.uploader()).md5file(file, 0, 10 * 1024 * 1024)
                            .progress(function (percentage) {
                                console.log("正在读取文件");
                            })
                            .then(function (val) {
                                filemd5 = val;
                                fm.push(filemd5); 
                                deferred.resolve();
                            });
                        return deferred.promise();
                    },
                    //时间点2:如果有分块上传,则每个分块上传之前调用此函数
                    beforesend: function (block) {
                        var deferred = webuploader.deferred();
 
                        //上传前ajax检测一下此文件块是否已经上传
 
                        this.owner.options.formdata.filemd5 = filemd5;
                        this.owner.options.formdata.chunk = block.chunk;
                        deferred.resolve();
                        return deferred.promise();
                    },
                    //时间点3:所有分块上传成功后调用此函数
                    aftersendfile: function (file) {
                        var deferred = $.deferred();
                        $('#' + file.id).find('p.state').text('执行最后一步');
                        console.log(file);
                        console.log(file.guid);
                        $.ajax({
                            type: "post",
                            url: "/api/v1/check/filemerge",
                            data: {
                                guid: file.guid,
                                filemd5: fm[fnum],
                                filename: file.name
                            },
                            cache: false,
                            async: false,
                            success: function (response) {
                                fnum++;
                                console.log(response);
                                if (response.success == true) {
                                    datastate = response;
                                    flag = true;
                                } else {
                                    flag = false;
                                }
                                deferred.resolve();
                            },
                            error: function () {
                                fnum++;
                                datastate = undefined;
                                flag = false;
                                deferred.reject();
                            }
                        });
 
                        return deferred.promise();
                    }
                });
            uploader = webuploader.create({
                resize: false,
                filenumlimit: 10,
                swf: '/js/uploader.swf',
                server: '/api/v1/check/filesave',
                pick: '#picker',
                chunked: true,
                chunksize: 10 * 1024 * 1024,
                chunkretry: 5
                //, formdata: {
                //    guid: guid
                //}
            });
            uploader.on('beforefilequeued', function (file) {
                var isadd = false;
                for (var i = 0; i < fileext.length; i++) {
                    if (file.ext == fileext[i]) {
                        file.guid = webuploader.base.guid();
                        isadd = true;
                        break;
                    }
                }
                return isadd;
            });
            uploader.on('uploadbeforesend', function (object, data, headers) {
                //console.log(object);
                headers.authorization =token;
                data.guid = object.file.guid;
            });
            // 当有文件添加进来的时候
            uploader.on('filequeued', function (file) {
                $list.append('<div id="' + file.id + '" class="item">' +
                    '<h4 class="info">' + file.name + '</h4>' +
                    '<input type="hidden" id="h_' + file.id + '" value="' + file.guid + '" />' +
                    '<p class="state">等待上传...</p>' +
                    '</div>');
            });
 
            // 文件上传过程中创建进度条实时显示。
            uploader.on('uploadprogress', function (file, percentage) {
                var $li = $('#' + file.id),
                    $percent = $li.find('.progress .progress-bar');
                // 避免重复创建
                if (!$percent.length) {
                    $percent = $('<div class="progress progress-striped active">' +
                        '<div class="progress-bar" role="progressbar" style="width: 0%">' +
                        '</div>' +
                        '</div>').appendto($li).find('.progress-bar');
                }
                $li.find('p.state').text('上传中');
 
                $percent.css('width', percentage * 100 + '%');
            });
 
            uploader.on('uploadsuccess', function (file) {
                if (datastate == undefined) {
                    $('#' + file.id).find('p.state').text('上传失败');
                    $('#' + file.id).find('button').remove();
                    $('#' + file.id).find('p.state').before('<button id="retry" type="button" class="btn btn-primary fright retry pbtn">重新上传</button>');
                    flag = false;
                    file.setstatus('error');
                }
                if (datastate.success == true) {
                    $('#' + file.id).find('p.state').text('已上传');
                    $('#' + file.id).find('button').remove();
 
                } else {
                    $('#' + file.id).find('p.state').text('上传失败');
                    flag = false;
                }
            });
 
            uploader.on('uploaderror', function (file) {
                $('#' + file.id).find('p.state').text('上传出错');
            });
 
            uploader.on('uploadcomplete', function (file) {
                $('#' + file.id).find('.progress').fadeout();
            });
 
            uploader.on('all', function (type) {
                if (type === 'startupload') {
                    state = 'uploading';
                } else if (type === 'stopupload') {
                    state = 'paused';
                } else if (type === 'uploadfinished') {
                    state = 'done';
                }
                if (state === 'done') {
                    $btn.text('继续上传');
                } else if (state === 'uploading') {
                    $btn.text('暂停上传');
                } else {
                    $btn.text('开始上传');
                }
            });
            $btn.on('click', function () {
                if (state === 'uploading') {
                    uploader.stop();
                } else if (state == 'done') {
                    window.location.reload();
                }
                else {
                    uploader.upload();
                }
            });
        });
    </script>
</head>
<body>
    <div id="uploader" class="wu-example">
        <span style="color:red">只能上传mpg、mpeg、mp4、avi格式的视频文件</span>
        <div id="thelist" class="uploader-list"></div>
        <div class="btns">
            <div id="picker" class="webuploader-container"><div class="webuploader-pick">选择文件</div><div style="position: absolute; top: 0px; left: 0px; width: 88px; height: 34px; overflow: hidden; bottom: auto; right: auto;"><input type="file" name="file" class="webuploader-element-invisible" multiple="multiple"><label style="opacity: 0; width: 100%; height: 100%; display: block; cursor: pointer; background: rgb(255, 255, 255);"></label></div></div>
            <button id="ctlbtn" class="btn btn-default">开始上传</button> 
        </div>
    </div>
</body>
</html>

后台代码:

#region 上传视频
        public iactionresult upload()
        {
            viewbag.token = httpcontext.request.headers["authorization"];//获取认证信息,传递给前台,方便ajax请求时提供
            return view();
        }
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <returns></returns>
        [httppost]
        public async task<iactionresult> filesave()
        {
            var date = request;
            var files = request.form.files;
            long size = files.sum(f => f.length);
            foreach (var formfile in files)
            {
                if (formfile.length > 0)
                {
                    string fileext = formfile.filename.substring(formfile.filename.indexof('.')); //文件扩展名,不含“.”
                    long filesize = formfile.length; //获得文件大小,以字节为单位
                    //string newfilename = guid.newguid().tostring() + "." + fileext; //随机生成新的文件名
                    string dirpath = path.combine(_uploadconfig.tmppath, request.form["guid"]);
                    if (!directory.exists(dirpath))
                    {
                        directory.createdirectory(dirpath);
                    }
                    var filepath = dirpath + "/" + request.form["chunk"] + fileext;
                    using (var stream = new filestream(filepath, filemode.create))
                    {
                        await formfile.copytoasync(stream);
 
                    }
                }
            }
            return ok(new { count = files.count, size });
        }
 
        /// <summary>
        /// 合并请求
        /// </summary>
        /// <returns></returns>
        [httppost]
        public async task<iactionresult> filemerge()
        {
            bool ok = false;
            string errmsg = "";
            try
            {
                var temporary = path.combine(_uploadconfig.tmppath, request.form["guid"]);//临时文件夹
                string filename = request.form["filename"];//文件名
                string fileext = path.getextension(filename);//获取文件后缀
                var files = directory.getfiles(temporary);//获得下面的所有文件
              
                var finalfilepath = path.combine(_uploadconfig.uploadpath + filename);//最终的文件名
                //var fs = new filestream(finalfilepath, filemode.create);
                using (var fs = new filestream(finalfilepath, filemode.create))
                {
                    foreach (var part in files.orderby(x => x.length).thenby(x => x))
                    {
                        var bytes = system.io.file.readallbytes(part);
                        await fs.writeasync(bytes, 0, bytes.length);
                        bytes = null;
                        system.io.file.delete(part);//删除分块
                    }
                    directory.delete(temporary);//删除文件夹
                    ok = true;
                }
            }
            catch (exception ex)
            {
                ok = false;
                errmsg = ex.message;
                log4net.error(errmsg);
            }
            if (ok)
            {
                return ok(new { success = true, msg = "" });
            }
            else
            {
                return ok(new { success = false, msg = errmsg }); ;
            }
        }
 
        #endregion