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

    感谢大哥   https://www.cnblogs.com/wdw984/p/11725118.html

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

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

    WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。

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

    直接上代码,前台cshtml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    @{
        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>

    后台代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    #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
  • 相关阅读:
    Redis-Sentinel 哨兵
    virtualenv and virtualenvwrapper
    C/C++中extern关键字详解
    C++ 中文拼音排序方法。
    vector排序
    VS2013 Ctrl+Shift+F 没反应
    PostMessage 解析
    CTextUI 文本控件 显示数字方法
    SetTimer API函数
    CEditUI 控件使用
  • 原文地址:https://www.cnblogs.com/ning-xiaowo/p/13153678.html
Copyright © 2011-2022 走看看