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

asp.net core分块上传文件示例

程序员文章站 2022-06-29 17:43:06
写完asp.net多文件上传后,感觉这种上传还是有很多缺陷,于是。。。(省略一万字,不废话)。这里我没用传统的asp.net,而选择了开源的asp.net core,原因很...

写完asp.net多文件上传后,感觉这种上传还是有很多缺陷,于是。。。(省略一万字,不废话)。这里我没用传统的asp.net,而选择了开源的asp.net core,原因很简单,.net core是.net新的开始,更是.net和.net开发者的未来,希望.net发展越来越好(大家的工资越来越高(●ˇ∀ˇ●))。

1.前端的实现:

1).html: 

<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>index</title>
  <link href="/lib/bootstrap/dist/css/bootstrap.css" rel="external nofollow" rel="stylesheet" />
  <script src="/lib/jquery/dist/jquery.js"></script>
  <script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
  <script src="/js/uploadjs.js"></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>

2).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!!!");
        }
      }
    }
  });
}

这里的主要思路是利用html5 file api的slice方法把文件分块,然后new一个formdata()对象用于储存文件数据,之后就是递归调用ajaxfile方法直至上传完毕。

2.后台c#:

using system;
using system.collections.generic;
using system.linq;
using system.threading.tasks;
using microsoft.aspnetcore.mvc;
using system.io;

// for more information on enabling mvc for empty projects, visit http://go.microsoft.com/fwlink/?linkid=397860

namespace dotnet.upload.controllers
{
  public class uploadcontroller : controller
  {
    // get: /<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(@"e:\浏览器", 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);
          });
        }
        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(@"e:\浏览器", lastmodified);//临时文件夹
        filename = request.form["filename"];//文件名
        string fileext = path.getextension(filename);//获取文件后缀
        var files = directory.getfiles(temporary);//获得下面的所有文件
        var finalpath = path.combine(@"e:\浏览器", 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真的非常好用),虽然不知道对效率有没有提升,但是就是觉得这样很酷。

源码下载:dotnet_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。