后台合并文件时,解决了并发合并冲突异常的情况。测试了2G文件上传,测试了4G文件上传,测试了8G文件上传,都成功了

前端代码方式一


<script src="~/Scripts/jquery-3.4.1.min.js"></script>
<div><input type="file" id="file" multiple="multiple" accept=".jpg,.png,.jpeg,.ai,.psd,.tif,.txt,.svg,.rar,.zip,.docx,.pptx,.xlsx,.iso" /><button id="upload">上传</button><div>进度:<span id="output">等待</span></div>
</div>
<script type="text/javascript">var page = {       //每批次最大发送请求数,设置太大浏览器会报异常net::ERR_INSUFFICIENT_RESOURCESconcurrentNum: 200, //上传成功的计数succeed: 0, //发送的文件分片下标forIndex: 0,//总分片数shardCount: 0,//每批次成功数eachIndex:0,//请求id//requestId:(new Date().getTime()/1000).toFixed(0),init: function () {$("#upload").click($.proxy(this.upload, this));},        sendData: function (i, file, shardSize, size, Count, name) {//计算每一片的起始与结束位置var start = i * shardSize,end = Math.min(size, start + shardSize);//构造一个表单,FormData是HTML5新增的var index = i + 1;var form = new FormData();form.append("data", file.slice(start, end));  //slice方法用于切出文件的一部分form.append("name",  "@DateTime.Now.Ticks"+name);            //form.append("name", this.requestId+name);form.append("total", Count);   //总片数form.append("index", index);        //当前是第几片$("#output").text(0 + " / " + page.shardCount);//Ajax提交$.ajax({url: "/Home/Upload?index=" + index,              type: "POST",data: form,async: true,         //异步processData: false,  //很重要,告诉jquery不要对form进行处理contentType: false,  //很重要,指定为false才能形成正确的Content-Typesuccess: function (s) {//alert(s);if (s.Code == 1) {//alert("上传失败!");console.log(s.Msg);} else {++page.succeed;++page.eachIndex;if (page.eachIndex >= page.concurrentNum && page.succeed <= page.shardCount) {console.log("page.succeed=" + page.succeed);console.log("page.eachIndex=" + page.eachIndex);//剩余数var remainder = Count - page.succeed;console.log("remainder="+remainder);//console.log("Count=" + Count + ",shardCount=" + page.shardCount);var xhSize = remainder > page.concurrentNum ? page.concurrentNum : remainder;console.log("xhSize=" + xhSize);console.log("forIndex=" + page.forIndex);                   for (var i=0; i < xhSize; ++page.forIndex) {page.sendData(page.forIndex, file, shardSize, size, Count, name);i++;}page.eachIndex = 0;}}$("#output").text(page.succeed + " / " + page.shardCount);if (page.succeed == page.shardCount) {page.succeed = 0;page.forIndex = 0;page.shardCount = 0;page.eachIndex = 0;$("#output").text("完成");}},error: function (e) {console.log(e);//alert(e);if (e.Code == 1) {//alert("上传失败!");}}});},upload: function () {page.succeed = 0;page.forIndex = 0;page.shardCount = 0;page.eachIndex = 0;var shardSize = 2 * 1024 * 1024;    //以2MB为一个分片for (var i = 0; i < $("#file")[0].files.length; i++) {page.shardCount += Math.ceil($("#file")[0].files[i].size / shardSize);   //总片数}for (var j = 0; j < $("#file")[0].files.length; j++) {var file = $("#file")[0].files[j],  //文件对象name = file.name,        //文件名size = file.size;        //总大小//var shardSize = 2 * 1024 * 1024,     //以2MB为一个分片//    shardCount = Math.ceil(size / shardSize);   //总片数var Count = Math.ceil(file.size / shardSize);//并发超过1300就会出错net::ERR_INSUFFICIENT_RESOURCES//小于1300的分片先处理,如果succeed==1300了,在处理余下的//var index2 = 0;var xhSize = Count > page.concurrentNum ? page.concurrentNum : Count;for (var i=0; i < xhSize; ++page.forIndex) {page.sendData(page.forIndex, file, shardSize, size, Count, name);i++;}                }}};$(function () {page.init();});
</script>

前端代码方式二(推荐)


<input type="file" id="file"  accept=".pdf,.jpg,.jpeg,.png,.gif,.bmp,.webp,.doc,.docx,.xls,.xlsx,.rtf,.ppt,.pptx,.zip,.rar" />
<a href="javascript:;" class="button org-btn small" id="addFile">上传</a>
<span>支持的文件格式:@string.Join("  ", CommonData.AllowFileUploadArr)</span>
<div>上传进度:<span id="progressStrip"></span></div>
<table class="layui-table"><thead><tr><th>文件名</th><th>大小</th><th>状态</th><th>操作</th></tr></thead>
<tbody id="demoList"></tbody>
</table>var fileMyUploder = {//每批次最大发送请求数,设置太大浏览器会报异常net::ERR_INSUFFICIENT_RESOURCESconcurrentNum: 200,//上传成功的计数succeed: 0,//发送的文件分片下标forIndex: 0,//总分片数shardCount: 0,//每批次成功数eachIndex:0,//请求idrequestId:(new Date().getTime()/1000).toFixed(0),uploadUrl:'',//上传后台处理地址doneFunc:function(){},//上传成功后回调方法sendData: function (i, file, shardSize, size, Count, name) {//计算每一片的起始与结束位置var start = i * shardSize,end = Math.min(size, start + shardSize);//构造一个表单,FormData是HTML5新增的var index = i + 1;var form = new FormData();form.append("data", file.slice(start, end));  //slice方法用于切出文件的一部分form.append("name", this.requestId+name);        form.append("total", Count);   //总片数form.append("index", index);        //当前是第几片$("#progressStrip").html(0 + " / " + fileMyUploder.shardCount);//Ajax提交$.ajax({//url: "/Home/Upload?index=" + index,url:fileMyUploder.uploadUrl+"?index=" + index,type: "POST",data: form,async: true,         //异步processData: false,  //很重要,告诉jquery不要对form进行处理contentType: false,  //很重要,指定为false才能形成正确的Content-Typesuccess: function (s) {//alert(s);if (s.Code == 1) {//alert("上传失败!");console.log(s.Msg);} else {++fileMyUploder.succeed;++fileMyUploder.eachIndex;if (fileMyUploder.eachIndex >= fileMyUploder.concurrentNum && fileMyUploder.succeed <= fileMyUploder.shardCount) {console.log("fileMyUploder.succeed=" + fileMyUploder.succeed);console.log("fileMyUploder.eachIndex=" + fileMyUploder.eachIndex);//剩余数var remainder = Count - fileMyUploder.succeed;console.log("remainder="+remainder);//console.log("Count=" + Count + ",shardCount=" + fileMyUploder.shardCount);var xhSize = remainder > fileMyUploder.concurrentNum ? fileMyUploder.concurrentNum : remainder;console.log("xhSize=" + xhSize);console.log("forIndex=" + fileMyUploder.forIndex);for (var i=0; i < xhSize; ++fileMyUploder.forIndex) {fileMyUploder.sendData(fileMyUploder.forIndex, file, shardSize, size, Count, name);i++;}fileMyUploder.eachIndex = 0;}}$("#progressStrip").html(fileMyUploder.succeed + " / " + fileMyUploder.shardCount);if (fileMyUploder.succeed == fileMyUploder.shardCount) {//console.log(s);fileMyUploder.doneFunc(s);//执行上传成功回调fileMyUploder.succeed = 0;fileMyUploder.forIndex = 0;fileMyUploder.shardCount = 0;fileMyUploder.eachIndex = 0;$("#progressStrip").html("完成");}},error: function (e) {console.log(e);//alert(e);if (e.Code == 1) {//alert("上传失败!");}}});},upload: function () {fileMyUploder.succeed = 0;fileMyUploder.forIndex = 0;fileMyUploder.shardCount = 0;fileMyUploder.eachIndex = 0;var shardSize = 2 * 1024 * 1024;    //以2MB为一个分片for (var i = 0; i < $("#file")[0].files.length; i++) {fileMyUploder.shardCount += Math.ceil($("#file")[0].files[i].size / shardSize);   //总片数}for (var j = 0; j < $("#file")[0].files.length; j++) {var file = $("#file")[0].files[j],  //文件对象name = file.name,        //文件名size = file.size;        //总大小var Count = Math.ceil(file.size / shardSize);var xhSize = Count > fileMyUploder.concurrentNum ? fileMyUploder.concurrentNum : Count;for (var i=0; i < xhSize; ++fileMyUploder.forIndex) {fileMyUploder.sendData(fileMyUploder.forIndex, file, shardSize, size, Count, name);i++;}}}
};fileMyUploder.uploadUrl = "/file/UploadBigFile";//上传后台处理地址fileMyUploder.doneFunc = function (d) {//上传成功后回调函数console.log("上传成功后回调函数:");console.log(d);var file = $("#file")[0].files[0];//文件对象console.log(file);var fileId = p.uuid();var fileSizeKb = (file.size / 1014).toFixed(1);var htmlArr = ['<tr id="' + fileId + '" fileSizeKb="' + fileSizeKb + '" OriginalFileName="' + file.name + '" durl="' + d.dbFileUrl+'">', '<td>' + file.name + '</td>', '<td>' + fileSizeKb + 'kb</td>', '<td  style="color: #5FB878;">上传成功</td>', '<td>', '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>', '</td>', '</tr>'];// 如果选的图片则显示出来var imageType = /image.*/;if (file.type.match(imageType)) {var reader = new FileReader();reader.onload = function () {var img = new Image();img.src = reader.result;//console.log(img);//console.log(img.outerHTML);$("#" + fileId + " td:first").html(img.outerHTML);};reader.readAsDataURL(file);}$("#demoList").append(htmlArr.join(''));//删除绑定$(".demo-delete").click(function () {$(this).parent().parent().remove();});} $("#addFile").click(function () {fileMyUploder.upload();});

后台代码:


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using WebApplicationFileUpload.Models;namespace WebApplicationFileUpload.Controllers
{public class HomeController : Controller{public ActionResult Index(){return View();}/// <summary>/// 并发合并检查/// </summary>static ConcurrentDictionary<string, string> checkMergeFile = new ConcurrentDictionary<string, string>();[HttpPost]public ActionResult Upload(){//从Request中取参数,注意上传的文件在Requst.Files中string name = Request["name"];int total = Convert.ToInt32(Request["total"]);int index = Convert.ToInt32(Request["index"]);var data = Request.Files["data"];try{//保存一个分片到磁盘上string dir = Server.MapPath("~/Upload");if (!Directory.Exists(dir)){Directory.CreateDirectory(dir);}string file = Path.Combine(dir, name + "_" + index);data.SaveAs(file);if (total - index < 20){string[] files = Directory.GetFiles(dir,name + "_*");LogHelpter.AddLog("total=" + total+ ",files.Length="+ files.Length);//如果已经是最后一个分片,组合//当然你也可以用其它方法比如接收每个分片时直接写到最终文件的相应位置上,但要控制好并发防止文件锁冲突if (files.Length == total){//判断是否已经有此文件在合并了,处理并发合并情况bool isMerge = checkMergeFile.Values.Contains(name);if (isMerge){LogHelpter.AddLog("阻止了一次并发合并文件");return Json(new { Code = 0, Msg = "上传成功" });}string chKey = Guid.NewGuid().ToString("N");checkMergeFile.TryAdd(chKey, name);LogHelpter.AddLog("checkMergeFile个数" + checkMergeFile.Count);System.Threading.Thread.Sleep(100);file = Path.Combine(dir, name);var fs = new FileStream(file, FileMode.Create);for (int i = 1; i <= total; ++i){string part = Path.Combine(dir, name + "_" + i);var bytes = System.IO.File.ReadAllBytes(part);fs.Write(bytes, 0, bytes.Length);bytes = null;System.IO.File.Delete(part);}fs.Close();fs.Dispose();     string outValue = string.Empty;checkMergeFile.TryRemove(chKey, out outValue);}}//数据库保存相对路径,生产环境一般存英文,  比如/upload/123444.jpgstring dbFileUrl = "/"+file.Replace(AppDomain.CurrentDomain.BaseDirectory,"").Replace(@"\", "/");//返回是否成功,此处做了简化处理return Json(new { Code = 0, Msg = "上传成功",url= dbFileUrl });}catch (Exception ex){return Json(new { Code = 1, Msg = ex.ToString() });}}}
}

参考了此文:
https://www.cnblogs.com/caijiabao/p/9662988.html

ASP.NET MVC大文件上传GB级相关推荐

  1. ASP.NET MVC之文件上传【一】(八)

    这一节我们来讲讲在MVC中如何进行文件的上传,我们逐步深入,一起来看看. Upload File(一) 我们在默认创建的项目中的Home控制器下添加如下: public ActionResult Up ...

  2. ASP.NET实现大文件上传和下载

    总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件 ...

  3. ASP.NET MVC图片文件上传与下载

    说明: 前后端代码中均只用到 ASP.NET MVC原生的技术,不需要用到ajax,WebAPI等. 下篇文章[ jQuery + Ajax + WebAPI 上传文件]会介绍使用Ajax POST来 ...

  4. Asp.net2.0下的大文件上传服务器控件

    最近本来准备在Alisoft上做点东西玩,做的过程中,涉及到了文件上传.刚开始,准备在网上找几个用,发现国外好用的要钱,而国内的,开源的又不好用,所以决定自己也写一个,顺便以后赚点外快.我看了一下,这 ...

  5. asp.net实现ftp上传代码(解决大文件上传问题)

    asp.net实现ftp上传代码(解决大文件上传问题) 参考文章: (1)asp.net实现ftp上传代码(解决大文件上传问题) (2)https://www.cnblogs.com/LYunF/ar ...

  6. ASP.NET 应用中大文件上传研究

    在项目中经常要用到了大文件上传,要上传的文件有100多m,于是研究现在国内使用的大文件上传的组件发现用的比较多的有两个控件AspnetUpload 2.0和Lion.Web.UpLoadModule, ...

  7. 大文件上传服务器:支持超大文件HTTP断点续传的实现办法

    点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 来源:blog.csdn.net/ababab12345/a ...

  8. Silverlight多文件(大文件)上传的开源项目

    在Silverlight上实现文件上传的例子在网上的还不多,特别是多文件上传和大文件上传的例子就更少了.当然 那些商品软件公司的产品除外. 目前的CodePlex上就有这样一个项目,其链接:http: ...

  9. 大文件上传和在线播放

    首先来说说大文件上传,用的WEB服务,代码如下. using System; using System.Collections; using System.ComponentModel; using ...

最新文章

  1. 栈与队列4——用一个栈实现另一个栈的排序
  2. 爬虫的系统框架组成-资源库
  3. mysql数据库木马查杀_Linux系统木马后门查杀方法详解
  4. pythondocx批量提取目录及内容_使用pythondocx搜索目录中的所有docx文件(批处理)...
  5. 泛洪攻击(Flood)与TCP代理(TCP proxy)
  6. c++ 0.你好,世界
  7. Java虚拟机内存区域---学习笔记
  8. 阿里AI界的新伙伴,1秒钟自动生成20000条文案
  9. mybatis 一对多查询 按结果嵌套处理、按查询嵌套处理,以及两者之间的区别
  10. SaltStack 第二板块安装说明 [2]
  11. Linux程序员必读:中文化与GB18030标准
  12. 使用lstm实现文本生成_Spamilton:使用LSTM和Hamilton歌词生成文本
  13. 全局空间自相关算法:Join Count
  14. ie11不兼容java_解决ie11不兼容的多个方法
  15. CPC系统在win10上的安装,1小时快速安装
  16. 问题:VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path
  17. 青龙面板之B站任务天选时刻
  18. 【Rosalind】Mortal Fibonacci Rabbits
  19. 关于常见的RuntimeException
  20. ubuntu小技巧6--如何修复Ubuntu系统引导项

热门文章

  1. 判断远程图片是否存在【适用于windows服务器】
  2. 近9成盗版Office用户称愿投奔开源(转)
  3. win7 虚拟wifi服务器,[转载]简单实用的建立WIN7的虚拟WIFI
  4. Google Glass众叛亲离?
  5. Rockchip RK3588 kernel dts解析之电源模块
  6. HT780S 编程软件 官方版 v1.07.04
  7. Access/VBA/Excel-两个表联合查询左连接-11
  8. x38和x48是服务器芯片吗,支持四卡交火!微星X48 Platinum白金版主板评测
  9. 如何成为一名合格的前端开发者?
  10. PHPStudy后门植入代码和利用分析