简单文件分块上传 c#后台
2018-08-10 11:42
52 查看
vue code
<style> .upload_warp_img_div_del { position: absolute; top: 6px; width: 16px; right: 4px; } .upload_warp_img_div_top { position: absolute; top: 0; width: 100%; height: 30px; background-color: rgba(0, 0, 0, 0.4); line-height: 30px; text-align: left; color: #fff; font-size: 12px; text-indent: 4px; } .upload_warp_img_div_text { white-space: nowrap; width: 80%; overflow: hidden; text-overflow: ellipsis; } .upload_warp_img_div img { max-width: 100%; max-height: 100%; vertical-align: middle; } .upload_warp_img_div { position: relative; /*height: 100px; width: 120px;*/ border: 1px solid #ccc; margin: 0px 30px 10px 0px; float: left; line-height: 100px; display: table-cell; text-align: center; background-color: #eee; cursor: pointer; } .upload_warp_img { border-top: 1px solid #D2D2D2; padding: 14px 0 0 14px; overflow: hidden; } .upload_warp_text { text-align: left; margin-bottom: 10px; padding-top: 10px; text-indent: 14px; border-top: 1px solid #ccc; font-size: 14px; } .upload_warp_right { float: left; width: 57%; margin-left: 2%; height: 100%; border: 1px dashed #999; border-radius: 4px; line-height: 130px; color: #999; } .upload_warp_left img { margin-top: 32px; } .upload_warp_left { /*float: left; width: 40%;*/ height: 100%; border: 1px dashed #999; border-radius: 4px; cursor: pointer; text-align:center; } .upload_warp { margin: 14px; height: 130px; } .upload { border: 1px solid #ccc; background-color: #fff; /*width: 650px;*/ box-shadow: 0px 1px 0px #ccc; border-radius: 4px; } .hello { width: 400px; /*margin-left: 34%;*/ } </style> <div class="page-container" id="RoundRobinOperate"> <div class="row cl"> <label class="form-label col-xs-4 col-sm-2">文件:</label> <div class="formControls col-xs-8 col-sm-9"> <div class="hello"> <label class="" style="color:red;" v-show="error_tips['ImgFile']!=''"><sup>*</sup>{{error_tips['ImgFile']}}</label> <div class="upload"> <div class="upload_warp"> <div class="upload_warp_left" @@click="fileClick('ImgFile')" @@drop="drop($event,'ImgFile')" @@dragenter="dragenter($event)" @@dragover="dragover($event)"> <img src="@Url.Content("~/Content/img/upload.png")"><br />點擊或將文件拖到此處 </div> </div> <div class="upload_warp_text"> 共{{bytesToSize(temp_ImgFile['ImgFile'].size)}} </div> <input @@change="fileChange($event,'ImgFile')" type="file" id="ImgFile" accept="image/png, image/jpeg, image/gif, image/jpg" style="display: none" /> <div class="upload_warp_img" v-show="temp_ImgFile['ImgFile'].url!=''"> <div class="upload_warp_img_div"> <div class="upload_warp_img_div_top"> <div class="upload_warp_img_div_text"> {{temp_ImgFile['ImgFile'].progress}} {{temp_ImgFile['ImgFile'].name}} </div> <img src="@Url.Content("~/Content/img/del.png")" class="upload_warp_img_div_del" @@click="fileDel('ImgFile')"> </div> <img :src="temp_ImgFile['ImgFile'].url"> </div> </div> </div> <button @@Click="readFile('ImgFile')" class="btn btn-primary radius" type="button"><i class="Hui-iconfont"></i> 上傳</button> </div> </div> </div> </div> <script type="text/javascript"> var _uploadFileUrl = "@Url.Content("~/RoundRobin/uploadFile")"; var _root_path = "@Url.Content("~/")"; $(function () { _vue_RoundRobinOperate = new Vue({ el: "#RoundRobinOperate", name: "RoundRobinOperate", data: function () { return { root_path: _root_path , temp_ImgFile: { ImgFile: { url: "", size: 0, progress: "", name: "" }, ImgFileTra: { url: "", size: 0, progress: "", name: "" }, ImgFileSimp: { url: "", size: 0, progress: "", name: "" } } , error_tips: { ImgFile: "", ImgFileTra: "", ImgFileSimp :"",submit:""} , imgList: {} , transmission_dataS:{} }; }, created: function () { }, methods: { fileClick(lang) { document.getElementById(lang).click(); }, fileChange(el, lang) { if (!el.target.files[0].size) return; this.fileAdd(el.target.files[0], lang); el.target.value = '' }, fileAdd(file, lang) { //判断是否为图片文件 不属于图片文件的话,给一个默认图片作为预览图 if (file.type.indexOf('image') == -1) { let _this = this; _this.temp_ImgFile[lang] = { url:"@Url.Content("~/Content/img/wenjian.png")", size: file.size, progress: "未上傳", name: file.name }; _this.imgList[lang] = file; } else { let reader = new FileReader(); let _this = this; reader.readAsDataURL(file); reader.onload = function () { _this.temp_ImgFile[lang] = { url: this.result, size: file.size, progress: "未上傳", name: file.name }; _this.imgList[lang] = file; } } }, fileDel(lang) { this.temp_ImgFile[lang] = { url: "", size: 0, progress: "", name: "" }; delete this.imgList[lang]; }, bytesToSize(bytes) { if (bytes === 0) return '0 B'; let k = 1000, // or 1024 sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], i = Math.floor(Math.log(bytes) / Math.log(k)); return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]; }, dragenter(el) { el.stopPropagation(); el.preventDefault(); }, dragover(el) { el.stopPropagation(); el.preventDefault(); }, drop(el, lang) { el.stopPropagation(); el.preventDefault(); this.fileAdd(el.dataTransfer.files[0], lang); }, uploadFile: function (pack, lang) { axios.post(_uploadFileUrl, { "data": pack }).then(function (response) { var obj = response.data; if (obj.type == 0 || obj.type == 1) { var pct = ((parseFloat(_vue_RoundRobinOperate.transmission_dataS[obj.packId].packIndex + 1) / parseFloat(_vue_RoundRobinOperate.transmission_dataS[obj.packId].packCount)) * 100).toFixed(2); _vue_RoundRobinOperate.temp_ImgFile[lang].progress = "上傳中 " + pct + "%"; //console.log(pct + "%"); } if (obj.type == 0) { var transmission_data = _vue_RoundRobinOperate.transmission_dataS[obj.packId]; transmission_data.packIndex = obj.packIndex; if (transmission_data.packIndex < transmission_data.packCount - 1) { _vue_RoundRobinOperate.sendPack(1, transmission_data, lang); } else { _vue_RoundRobinOperate.sendPack(2, transmission_data, lang); } } else if (obj.type == 1) { _vue_RoundRobinOperate.temp_ImgFile[lang].progress = "上傳成功"; if (lang == "ImgFile") { _vue_RoundRobinOperate.round_robin.ImgFile = obj.fileUrl; } else if (lang == "ImgFileTra") { _vue_RoundRobinOperate.round_robin.ImgFileTra = obj.fileUrl; } else if (lang == "ImgFileSimp") { _vue_RoundRobinOperate.round_robin.ImgFileSimp = obj.fileUrl; } delete _vue_RoundRobinOperate.transmission_dataS[obj.packId]; } else if (obj.type == 2) { var transmission_data = _vue_RoundRobinOperate.transmission_dataS[obj.packId]; transmission_data.packIndex = obj.packIndex; _vue_RoundRobinOperate.sendPack(2, transmission_data, lang); } }).catch(function (error) { console.info(error); setTimeout(function () { _vue_RoundRobinOperate.uploadFile(pack, lang); }, 5000); }); }, readFile: function (lang) { var file = this.imgList[lang];//input.files[0]; var query = {}; var chunks = []; var chunk = 1 * 1024 * 1024; //每片大小 if (!!file) { this.error_tips[lang] = ""; var temp0 = file.name.split('.'); var _extension = temp0[temp0.length - 1]; var start = 0; //文件分片 for (var i = 0, len1 = Math.ceil(file.size / chunk) ; i < len1 ; i++) { var end = start + chunk; chunks[i] = file.slice(start, end); start = end; } var packid = parseInt(Math.random() * 10000) + new Date().getTime(); this.transmission_dataS[packid] = { packCount: chunks.length, packIndex: 0, packId: packid, dataExtension: _extension, dataBuffer: chunks }; //console.log("file.name -》"); this.temp_ImgFile[lang].progress = "開始上傳"; this.sendPack(0, this.transmission_dataS[packid], lang); } else { this.error_tips[lang] = "請選擇文件,然後再點上傳"; } }, sendPack: function (type, transmission_data, lang) { var reader = new FileReader(); reader.readAsDataURL(transmission_data.dataBuffer[transmission_data.packIndex]); reader.onload = function (e) { //Type_Count_Id_Index_Data_key_extension //Type 0-包开始 1-包传输中 2-包结束 //key MD5(Type+Count+Id+Index) var Count = transmission_data.packCount; var Index = transmission_data.packIndex; var Id = transmission_data.packId; var data = this.result; var Type = type; var key = Type + Count + Id + Index; var extension = transmission_data.dataExtension; var pack = Type + "_" + Count + "_" + Id + "_" + Index + "_" + data + "_" + key + "_" + extension; _vue_RoundRobinOperate.uploadFile(pack, lang); } } } }); }); </script>
c# 后台代码
//定义全局变量 public ActionResult index() { if (System.Web.HttpContext.Current.Cache["MyDictionary"] == null) { ConcurrentDictionary<string, List<MyDictionaryValueModel>> MyDictionary = new ConcurrentDictionary<string, List<MyDictionaryValueModel>>(); System.Web.HttpContext.Current.Cache["MyDictionary"] = MyDictionary; } return View(); } #region 上傳 public class MyDictionaryValueModel { public string Id { get; set; } public string[] Data { get; set; } public int Index { get; set; } } public JsonResult uploadFile(string data) { //Type_Count_Id_Index_Data_key_extension //Type 0-包开始 1-包传输中 2-包结束 //key MD5(Type+Count+Id+Index) string temp_folder = string.Empty; string upload_folder = CommonService.ConfigurationManagerService.RoundRobinManageFolder; string root = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase; try { string UserId = GeneralMethods.GetCurrent().LoginName; var dataArry = data.Split('_'); if (dataArry.Length == 7) { string Type = dataArry[0], Count = dataArry[1], Id = dataArry[2], Index = dataArry[3], Data = dataArry[4], key = dataArry[5], extension = dataArry[6]; ConcurrentDictionary<string, List<MyDictionaryValueModel>> MyDictionary = (ConcurrentDictionary<string, List<MyDictionaryValueModel>>)System.Web.HttpContext.Current.Cache["MyDictionary"]; if (Type == "0") { if (!MyDictionary.ContainsKey(UserId)) { MyDictionary.TryAdd(UserId, new List<MyDictionaryValueModel>()); } MyDictionary[UserId].Add(new MyDictionaryValueModel { Id = Id, Data = new string[Convert.ToInt32(Count)], Index = 0 }); } var ValueModel = MyDictionary[UserId].Where(d => d.Id == Id).FirstOrDefault(); ValueModel.Data[Convert.ToInt32(Index)] = "received"; //------ 把文件块 保存到临时文件夹 var btsdata = Convert.FromBase64String(Data.Split(',')[1]); temp_folder = root + upload_folder + @"/"+Id; if (!Directory.Exists(temp_folder)) { Directory.CreateDirectory(temp_folder); } string file1 = temp_folder + @"/" + Index + "." + "temp";//文件块 using (FileStream fs = new FileStream(file1, FileMode.Create)) { fs.Write(btsdata, 0, btsdata.Length); fs.Close(); } //------ if (Convert.ToInt32(Count) == 1 || Type == "2") { bool data_is_complete = true; for (int i = 0, len = ValueModel.Data.Length; i < len; i++) { var tempdata = ValueModel.Data[i]; if (tempdata == null) { data_is_complete = false; //通知客户端 重新发送丢失的包 return Json(new { type =2, packId =Id, packIndex =i}, JsonRequestBehavior.AllowGet); } } if (data_is_complete) { string uploadDir = root + upload_folder; if (!Directory.Exists(uploadDir)) { Directory.CreateDirectory(uploadDir); } string file_name = upload_folder + @"/" + Guid.NewGuid().ToString("D") +"-"+ DateTime.Now.ToString("HHmmssfff") + "." + extension; string file = root + file_name; using (FileStream fs = new FileStream(file, FileMode.Create)) {//从临时文件夹,读取文件块,合并到同一个文件 for (int i = 0, len = Convert.ToInt32(Count); i < len; i++) { string file2 = temp_folder + @"/" + i.ToString() + "." + "temp"; var tempBytes = System.IO.File.ReadAllBytes(file2); fs.Write(tempBytes, 0, tempBytes.Length); } fs.Close(); } DeleteFolder(temp_folder);//删除临时文件 Directory.Delete(temp_folder, true);//删除临时文件夹 MyDictionary[UserId].Remove(ValueModel); return Json(new { type = 1, packId = Id,fileUrl= file_name }, JsonRequestBehavior.AllowGet); } } else { //通知客户端 已接收到 ValueModel.Index++; return Json(new { type = 0, packId = Id ,packIndex = ValueModel.Index }, JsonRequestBehavior.AllowGet); } } } catch (Exception ex) { if (temp_folder != string.Empty) { DeleteFolder(temp_folder); Directory.Delete(temp_folder, true); } //throw ex; JsonResult result = new JsonResult(); result.MaxJsonLength = int.MaxValue; result.Data = new { type = -1, message = ex.ToString() }; return result; } return Json(new { type = -1, message = "param error" }, JsonRequestBehavior.AllowGet); } public void DeleteFolder(string dir) { System.Threading.Tasks.Parallel.ForEach(Directory.GetFileSystemEntries(dir), (d) => { try { if (System.IO.File.Exists(d)) { FileInfo fi = new FileInfo(d); if (fi.Attributes.ToString().ToLower().IndexOf("readonly") != -1) fi.Attributes = FileAttributes.Normal; System.IO.File.Delete(d);//直接删除其中的文件 } else { DirectoryInfo d1 = new DirectoryInfo(d); if (d1.GetFiles().Length != 0) { DeleteFolder(d1.FullName);////递归删除子文件夹 } Directory.Delete(d); } } catch { } }); if (Directory.GetFileSystemEntries(dir).Length > 0) { DeleteFolder(dir); } } #endregion
注:
1.websocket、signalr同理可得
2.注意文件分块,每块的大小,不适宜太大,会受到传输限制,上传失败时,可以尝试调整大小,目前设置的是每块1M
3.欢迎拍砖,反正我也不改
相关文章推荐
- sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)
- 文件上传简单案例(后台Servlet处理)
- 一个简单的QQ隐藏图生成算法 通过jQuery和C#分别实现对.NET Core Web Api的访问以及文件上传
- c#多文件上传简单实现
- 纯js实现最简单的文件上传(后台使用MultipartFile)
- C#简单实现文件上传功能
- [每天一个demo]用c#实现简单的上传文件程序
- C#2.0简单ftp文件上传方法
- C#文件上传的简单实现
- C#后台判断上传文件大小
- C# 文件上传简单示例
- resumable.js —— 基于 HTML 5 File API 的文件上传组件 支持续传后台c#实现
- C#.net 通过后台 上传文件案例
- C#后台代码 Post 提交表单上传文件及其他信息
- asp.net,C#,FileUpload控件文件上传简单实例,vs2010
- java 文件上传 与 把文件解析成一个字节数组简单的后台示例
- C# 客服端上传文件与服务器器端接收 (简单代码)
- c#.net上传文件到数据库中(把文件转换成二进制流存在后台数据库)
- C# 如何后台判断 file控件上传的文件类型
- asp.net,C#,html控件的File控件文件上传简单实例,vs2010