zoukankan      html  css  js  c++  java
  • .NetCore+WebUploader实现大文件分片上传

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

    使用了开源的前台上传插件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=" 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;  88px; height: 34px; overflow: hidden; bottom: auto; right: auto;"><input type="file" name="file" class="webuploader-element-invisible" multiple="multiple"><label style="opacity: 0;  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
    

     

  • 相关阅读:
    ~~网络编程(六):自定义报头~~
    ~~网络编程(五):粘包现象~~
    ~~网络编程(四):socket套接字~~
    ~~网络编程(三):TCP/UDP~~
    ~~网络编程(二):层级初识~~
    Java的异常处理方式
    Java中的泛型
    Collection接口综述
    匿名内部类和局部内部类只能访问final变量的原因
    Java内部类
  • 原文地址:https://www.cnblogs.com/wdw984/p/11725118.html
Copyright © 2011-2022 走看看