• 一、.Net Core 分块上传文件


    一、.Net Core 分块上传文件

    一、前端实现

    @*
        For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
    *@
    @{
        ViewData["Title"] = "Index";
        Layout = null;
    }
    <!DOCTYPE html>
    
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
        <link href="https://cdn.bootcss.com/webuploader/0.1.1/webuploader.css" rel="stylesheet">
        <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    
        <script type="text/javascript">
            var UploadPath = "";
            //开始上传
            function UploadStart() {
                var file = $("#path")[0].files[0];
                AjaxFile(file, 0);
            }
            function AjaxFile(file, i) {
                var name = file.name, //文件名
                    size = file.size, //总大小shardSize = 2 * 1024 * 1024,
                    shardSize = 2 * 1024 * 1024,//以2MB为一个分片
                    shardCount = Math.ceil(size / shardSize); //总片数
                if (i >= shardCount) {
                    return;
                }
                //计算每一片的起始与结束位置
                var start = i * shardSize,
                    end = Math.min(size, start + shardSize);
                //构造一个表单,FormData是HTML5新增的
                var form = new FormData();
                form.append("data", file.slice(start, end)); //slice方法用于切出文件的一部分
                form.append("lastModified", file.lastModified);
                form.append("fileName", name);
                form.append("total", shardCount); //总片数
                form.append("index", i + 1); //当前是第几片
                UploadPath = file.lastModified
                //Ajax提交文件
                $.ajax({
                    url: "/Upload/UploadFile",
                    type: "POST",
                    data: form,
                    async: true, //异步
                    processData: false, //很重要,告诉jquery不要对form进行处理
                    contentType: false, //很重要,指定为false才能形成正确的Content-Type
                    success: function (result) {
                        if (result != null) {
                            i = result.number++;
                            var num = Math.ceil(i * 100 / shardCount);
                            $("#output").text(num + '%');
                            AjaxFile(file, i);
                            if (result.mergeOk) {
                                var filepath = $("#path");
                                filepath.after(filepath.clone().val(""));
                                filepath.remove();//清空input file
                                $('#upfile').val('请选择文件');
                                alert("success!!!");
                            }
                        }
                    }
                });
            }
        </script>
    
    </head>
    <body>
        <div class="row" style="margin-top:20%">
            <div class="col-lg-4"></div>
            <div class="col-lg-4">
                <input type="text" value="请选择文件" size="20" name="upfile" id="upfile" style="border:1px dotted #ccc">
                <input type="button" value="浏览" onclick="path.click()" style="border:1px solid #ccc;background:#fff">
                <input type="file" id="path" style="display:none" multiple="multiple" onchange="upfile.value=this.value">
                <br />
                <span id="output">0%</span>
                <button type="button" id="file" onclick="UploadStart()" style="border:1px solid #ccc;background:#fff">开始上传</button>
            </div>
            <div class="col-lg-4"></div>
        </div>
    </body>
    </html>

    这里的主要思路是利用html5 File api的slice方法把文件分块,

    然后new一个FormData()对象用于储存文件数据,之后就是递归调用AjaxFile方法直至上传完毕。

    后台代码:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApplication2.Controllers
    {
        public class UploadController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
    
            [HttpPost]
            public async Task<ActionResult> UploadFile()
            {
                var data = Request.Form.Files["data"];
                string lastModified = Request.Form["lastModified"].ToString();
                var total = Request.Form["total"];
                var fileName = Request.Form["fileName"];
                var index = Request.Form["index"];
    
                string temporary = Path.Combine(@"D:浏览器", lastModified);//临时保存分块的目录
                try
                {
                    if (!Directory.Exists(temporary))
                        Directory.CreateDirectory(temporary);
                    string filePath = Path.Combine(temporary, index.ToString());
                    if (!Convert.IsDBNull(data))
                    {
                        await Task.Run(() => {
                            FileStream fs = new FileStream(filePath, FileMode.Create);
                            data.CopyTo(fs);
                            fs.Close();
                        });
                    }
                    bool mergeOk = false;
                    if (total == index)
                    {
                        mergeOk = await FileMerge(lastModified, fileName);
                    }
    
                    Dictionary<string, object> result = new Dictionary<string, object>();
                    result.Add("number", index);
                    result.Add("mergeOk", mergeOk);
                    return Json(result);
    
                }
                catch (Exception ex)
                {
                    Directory.Delete(temporary);//删除文件夹
                    throw ex;
                }
            }
    
            public async Task<bool> FileMerge(string lastModified, string fileName)
            {
                bool ok = false;
                try
                {
                    var temporary = Path.Combine(@"D:浏览器", lastModified);//临时文件夹
                    fileName = Request.Form["fileName"];//文件名
                    string fileExt = Path.GetExtension(fileName);//获取文件后缀
                    var files = Directory.GetFiles(temporary);//获得下面的所有文件
                    var finalPath = Path.Combine(@"D:浏览器", DateTime.Now.ToString("yyMMddHHmmss") + fileExt);//最终的文件名(demo中保存的是它上传时候的文件名,实际操作肯定不能这样)
                    var fs = new FileStream(finalPath, FileMode.Create);
                    foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序,保证从0-N Write
                    {
                        var bytes = System.IO.File.ReadAllBytes(part);
                        await fs.WriteAsync(bytes, 0, bytes.Length);
                        bytes = null;
                        System.IO.File.Delete(part);//删除分块
                    }
                    fs.Close();
                    Directory.Delete(temporary);//删除文件夹
                    ok = true;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                return ok;
            }
    
    
        }
    }

     这里的思路就是先保存每一个分块的文件到一个临时文件夹,

    最后再通过FileStream合并这些临时文件(合并时必需要按顺序)。

    后台的方法都进行了异步化(async await真的非常好用),

    虽然不知道对效率有没有提升,但是就是觉得这样很酷。

  • 相关阅读:
    爬虫总结
    Request模块(八)
    urllib2异常处理(七)
    urllib2 Handler处理器和自定义opener(六)
    urllib2的GET和POST请求(五)
    urllib2模块的基本使用(四)
    HTTP代理器Fiddler(三)
    http协议再复习(二)
    Spring.NET学习笔记6——依赖注入(应用篇)
    4.spring对象的创建(静态工厂 实例工厂 泛型,嵌套类型)
  • 原文地址:https://www.cnblogs.com/fger/p/11293277.html
Copyright © 2020-2023  润新知