WEB上传大文件解决方案
众所皆知,web上传大文件,一直是一个痛。上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的。
本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路。下面贴出简易DEMO源码分享:
前端页面:
@{ ViewBag.Title = "Upload"; } <h2>Upload</h2> <table class="table table-striped"> <tr> <td><input type="file" id="file" onchange="selfile()" /></td> <td><input type="button" value="上传" onclick="uploading()" /></td> </tr> <tr> <td colspan="2">文件信息:<span id="fileMsg"></span></td> </tr> <tr> <td colspan="2">当前进度:<span id="upsize"></span></td> </tr> </table> <script src="~/Scripts/myUploader.js"></script> <script type="text/javascript"> //guid var guid = "@Guid.NewGuid()"; var uploader; function selfile() { var f = $("#file")[0].files[0]; uploader = new SupperUploader("@Url.Action("RecvUpload")", f, guid, (1024*1024)); $("#fileMsg").text("文件名:" + uploader.fileName + "文件类型:" + uploader.fileType + "文件大小:" + uploader.fileSize + "字节"); } function uploading() { uploader.UploadFun(function () { $("#upsize").text(uploader.upedSize); }) } </script>
SupperUploader是我自己封装的JS插件,源码如下:
var SupperUploader = function (uploadUrl, file, guid, cutSize) { this.file = file; //文件大小 this.fileSize = file.size; //文件类型 this.fileType = file.type; //文件路径 this.fileName = file.name; //guid this.guid = guid; //分片大小 this.cutSize = cutSize, //已上传 this.upedSize = 0; //开始位置 this.startIndex = 0; //结束位置 this.endIndex = 0; //序号 this.indexr = 0; //上传路径 this.uploadUrl = uploadUrl; //合并结果 this.merged = false; }; SupperUploader.prototype = { UploadFun: function (uploadCallBack) { if (this.merged) return; var thisobj = this; $.ajax({ type: "POST", url: thisobj.uploadUrl, enctype: 'multipart/form-data', data: thisobj.CutFileFun(), processData: false, contentType: false, success: function (res) { if (res == "success") { if (thisobj.upedSize == thisobj.fileSize) { thisobj.merged = true; alert("已成功上传!") return; } thisobj.upedSize += thisobj.cutSize; if (thisobj.upedSize > thisobj.fileSize) thisobj.upedSize = thisobj.fileSize; thisobj.indexr+=1; //执行回调函数 uploadCallBack(); //继续调用上传 thisobj.UploadFun(uploadCallBack); } } }); }, CutFileFun: function () { var formData = null; if (this.upedSize < this.fileSize) { this.startIndex = this.upedSize; this.endIndex = this.startIndex + this.cutSize; if (this.endIndex > this.fileSize) { this.endIndex = this.fileSize; } var currentData = this.file.slice(this.startIndex, this.endIndex); formData = new FormData(); formData.append("file", currentData); formData.append("index", this.indexr); formData.append("fname", this.fileName); formData.append("guid", this.guid); formData.append("ismerge", this.fileSize == this.endIndex); } return formData; } };
后端代码,此Demo是基于MVC架构的:
[HttpGet] public ActionResult Upload() { return View(); } [HttpPost] public ActionResult RecvUpload(){ try { string fileName = Request["fname"]; string index = Request["index"]; string guid = Request["guid"]; var file = Request.Files[0]; var ismerge = Request["ismerge"]; string tempDirpath = "~/Content/temp/" + guid + "/"; string savepath = tempDirpath + index + "_" + fileName; //合并文件 if (bool.Parse(ismerge)) { //获取所有分割文件 var files = System.IO.Directory.GetFiles(Server.MapPath(tempDirpath)); //文件FILEINFO var infos = files.Select(x => new FileInfo(x)).ToList().OrderBy(x=>x.LastWriteTime).ToList(); //合并文件流 FileStream mergefs = new FileStream(Server.MapPath("~/Content/temp/" + fileName),FileMode.Append); BinaryWriter bw = new BinaryWriter(mergefs); FileStream tempfs = null; BinaryReader tempbr= null; infos.ToList().ForEach(f => { tempfs = new FileStream(f.FullName, FileMode.Open); tempbr = new BinaryReader(tempfs); bw.Write(tempbr.ReadBytes((int)tempfs.Length)); tempfs.Close(); tempbr.Close(); }); bw.Close(); mergefs.Close(); //删除分块文件 infos.ForEach(f =>{ System.IO.File.Delete(f.FullName); }); return Json("success"); } if (!System.IO.Directory.Exists(Server.MapPath(tempDirpath))){ System.IO.Directory.CreateDirectory(Server.MapPath(tempDirpath)); } using (FileStream fs = new FileStream(Server.MapPath(savepath), FileMode.CreateNew)) { using (Stream stream = file.InputStream) { byte[] buffer = new byte[stream.Length]; stream.Read(buffer, 0, (int)stream.Length); fs.Write(buffer, 0, buffer.Length); } } return Json("success"); } catch (Exception e) { return Json(e.Message); } }
在此分享!希望多多指正~