写在前面:
项目需要 , 以前 做过一个单文件在2G以下 可以多个文件上传至服务器的功能,客户 不满足, 参考了很多前辈们的代码,在网上也找了不少 ,然后总结出来了一个 ,做一下总结。
aspx:
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="css/flieUpoload.css" rel="stylesheet" /> <title></title> </head> <body> <form id="form1" runat="server"> <div> <div class="container"> <input type="file" name="fileselect" id="fileselect" value="" multiple /> <input type="button" id="btnselect" value="选择上传的文件" /> <input type="button" id="btnupload" value="开始上传" /> </div> <table cellspacing="0" cellpadding="0" id="filelist"> <tr> <td class="filename">文件名</td> <td class="fileprogress">进度</td> <td class="filestatus">状态</td> </tr> <tr id="trmsg"> <td colspan="3" id="tdmsg">请选择要上传的文件</td> </tr> </table> <script src="js/jquery-1.10.2.min.js"></script> <script src="js/spark-md5.min.js"></script> <script src="js/FileUpoload.js"></script> </div> </form> </body> </html>
css:
*{ font-family: "微软雅黑"; margin: 0; padding: 0; } .container { padding-top: 10px; padding-left: 10px; } .container input { 120px; height: 30px; background-color: blue; color: white; border: 0; line-height: 30px; border-radius: 5px; margin-right: 5px; outline: none; cursor: pointer; } #filelist { 800px; border: solid 1px #eee; border-collapse: collapse; margin: 10px; } #filelist td { border-bottom: solid 1px #eee; height: 30px; font-size: 12px; padding: 0 3px; } .filename { 200px; text-align: center; } .filestatus { 100px; text-align: center; } .fileprogress { text-align: center; } .domprogress { 320px; } .domsize { display: block; } #tdmsg { text-align: center; } #fileselect { display: none; } span.domtime { display: block; }
js:
$("#btnselect").click(function () { $("#fileselect").click(); }); $("#fileselect").change(function () { var files = this.files; if (files.length > 0) { $("#trmsg").remove(); $(files).each(function (index, item) { console.log(index, item); var filesize = 0; if ((item.size / 1024 / 1024 / 1024) >= 1) { filesize = (item.size / 1024 / 1024 / 1024).toFixed(2) + "GB"; // b=>kb=>mb=>gb } else if ((item.size / 1024 / 1024 / 1024) < 1 && (item.size / 1024 / 1024) >= 1) { filesize = (item.size / 1024 / 1024).toFixed(2) + "MB"; } else if ((item.size / 1024 / 1024) < 1 && (item.size / 1024) >= 1) { filesize = (item.size / 1024).toFixed(2) + "KB"; } else { filesize = item.size + "B"; } var htmlstr = '<tr><td>' + item.name + '</td><td><progress value="0" max="100" class="domprogress"></progress><span class="dompercent"> 0/' + filesize + '</span><span class="domtime">总共耗时:0 秒</span></td><td class="filestatus"><span class="domstatus">排队中</span></td></tr>'; $("#filelist").append(htmlstr); }); } }); $.ajaxSetup({ async: false }); $("#btnupload").click(function () { var files = $("#fileselect")[0].files; $.ajaxSettings.async = false; $(files).each(function (index, item) { yyupload(files[index], $("span.domstatus").eq(index), $("span.dompercent").eq(index), $(".domprogress").eq(index), $("span.domtime").eq(index)); }); $.ajaxSettings.async = true; }); //文件上传 function yyupload(file, dommsg, dompercentmb, domprogress, domtime, fn) { var startTime = new Date(); //获取文件的md5字符串,用于标识文件的唯一性。 calculate(file); //获取文件的加密字符串 function calculate(file) { var fileReader = new FileReader(); var chunkSize = 1024 * 1024 * 5; //每次读取5MB var chunksCount = Math.ceil(file.size / chunkSize); //回大于参数x的最小整数 8=》8 8.4=》9 8.5=》9 -8.5=》-8 var currentChunk = 0; //当前块的索引 var spark = new SparkMD5(); fileReader.onload = function (e) { //console.log((currentChunk + 1) + "/" + chunksCount) dommsg.text("正在检查文件: " + (currentChunk + 1) + "/" + chunksCount); spark.appendBinary(e.target.result); // 添加二进制字符串 currentChunk++; if (currentChunk < chunksCount) { loadNext(); } else { var md5value = spark.end(); //console.log("文件加密结束,密钥为:" + md5value); checkfile(md5value, file); //检查服务器是否存在该文件,存在就从断点继续上传 } }; function loadNext() { var start = currentChunk * chunkSize; //计算读取开始位置 var end = start + chunkSize >= file.size ? file.size : start + chunkSize; //计算读取结束位置 fileReader.readAsText(file.slice(start, end)); //读取为二进制字符串readAsBinaryString }; loadNext(); } var repeatcount = 0; //检查文件是否已经存在 function checkfile(md5value, file) { //var Id = GetQueryString("Id"); $.ajaxSettings.async = false; var fd = new FormData(); fd.append('rquesttype', "chekcfile"); fd.append('filename', file.name); fd.append('md5value', md5value); //fd.append('type', GetQueryString("type")) //fd.append('Id', Id); var xhr = new XMLHttpRequest(); xhr.open('post', 'FileUpoload.ashx', true); xhr.onreadystatechange = function (res) { if (xhr.readyState == 4 && xhr.status == 200) { var jsonobj = JSON.parse(xhr.responseText); //可以将json字符串转换成json对象 //JSON.stringify(jsonobj); //可以将json对象转换成json对符串 console.log("继续上传的位置:" + jsonobj.startindex); switch (jsonobj.flag) { case "0": doUpload(md5value, file, 0); break; case "1": doUpload(md5value, file, parseInt(jsonobj.startindex)); break; case "2": secondUpload(file); domtime.text("此文件已经存在,无法继续上传。"); break; } repeatcount = 0; } else if (xhr.status == 500) { setTimeout(function () { if (repeatcount < 3) { checkfile(md5value, file); } repeatcount++; }, 3000); } } //开始发送 xhr.send(fd); $.ajaxSettings.async = true; } function secondUpload(file) { var timerange = (new Date().getTime() - startTime.getTime()) / 1000; domtime.text("耗时" + timerange + "秒"); //显示结果进度 var percent = 100; dommsg.text(percent.toFixed(2) + "%"); domprogress.val(percent); var total = file.size; if (total > 1024 * 1024 * 1024) { dompercentmb.text((total / 1024 / 1024 / 1024).toFixed(2) + "GB/" + (total / 1024 / 1024 / 1024).toFixed(2) + "GB"); } else if (total > 1024 * 1024) { dompercentmb.text((total / 1024 / 1024).toFixed(2) + "MB/" + (total / 1024 / 1024).toFixed(2) + "MB"); } else if (total > 1024 && total < 1024 * 1024) { dompercentmb.text((total / 1024).toFixed(2) + "KB/" + (total / 1024).toFixed(2) + "KB"); } else { dompercentmb.text((total).toFixed(2) + "B/" + (total).toFixed(2) + "B"); } } //上传文件 function doUpload(md5value, file, startindex) { var reader = new FileReader() var step = 1024 * 200; var cuLoaded = startindex; var total = file.size; //读取一段成功 reader.onload = function (e) { //处理读取的结果 var result = reader.result; //本次读取的数据 var loaded = e.loaded; //本次读取的数据长度 uploadFile(result, cuLoaded, function () { //将分段数据上传到服务器 cuLoaded += loaded; //如果没有读完,继续 var timerange = (new Date().getTime() - startTime.getTime()) / 1000; if (total > 1024 * 1024 * 1024) { dompercentmb.text((cuLoaded / 1024 / 1024 / 1024).toFixed(2) + "GB/" + (total / 1024 / 1024 / 1024).toFixed(2) + "GB"); } else if (total > 1024 * 1024) { dompercentmb.text((cuLoaded / 1024 / 1024).toFixed(2) + "MB/" + (total / 1024 / 1024).toFixed(2) + "MB"); } else if (total > 1024 && total < 1024 * 1024) { dompercentmb.text((cuLoaded / 1024).toFixed(2) + "KB/" + (total / 1024).toFixed(2) + "KB"); } else { dompercentmb.text((cuLoaded).toFixed(2) + "B/" + (total).toFixed(2) + "B"); } domtime.text("耗时" + timerange + "秒"); if (cuLoaded < total) { readBlob(cuLoaded); } else { console.log('总共用时:' + timerange); cuLoaded = total; sendfinish(); //告知服务器上传完毕 domtime.text("上传完成,总共耗时" + timerange + "秒"); } //显示结果进度 var percent = (cuLoaded / total) * 100; dommsg.text(percent.toFixed(2) + "%"); domprogress.val(percent); }); } var k = 0; function sendfinish() { $.ajaxSettings.async = false; var fd = new FormData(); fd.append('rquesttype', "finishupload"); fd.append('filename', file.name); fd.append('md5value', md5value); fd.append('totalsize', file.size); fd.append('type', GetQueryString("type")); fd.append('id', GetQueryString("id")); //fd.append('type', GetQueryString("type")) var xhr = new XMLHttpRequest(); xhr.open('post', 'FileUpoload.ashx', true); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { if (fn) { fn(); //如果上传成功,继续上传下一个文件 } k = 0; } else if (xhr.status == 500) { setTimeout(function () { if (k < 3) { sendfinish(); //上传完毕的前端处理 } k++ }, 3000); } } //开始发送 xhr.send(fd); $.ajaxSettings.async = true; } var m = 0; //关键代码上传到服务器 function uploadFile(result, startIndex, onSuccess) { var blob = new Blob([result]); //提交到服务器 $.ajaxSettings.async = false; var fd = new FormData(); fd.append('file', blob); fd.append('rquesttype', "uploadblob"); fd.append('filename', file.name); fd.append('md5value', md5value); fd.append('loaded', startIndex); var xhr = new XMLHttpRequest(); xhr.open('post', 'FileUpoload.ashx', true); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { m = 0; if (onSuccess) onSuccess(); } else if (xhr.status == 500) { setTimeout(function () { if (m < 3) { containue(); m++; } }, 1000); } } xhr.send(fd); $.ajaxSettings.async = true; } function readBlob(start) { var blob = file.slice(start, start + step); reader.readAsArrayBuffer(blob); } function containue() { readBlob(cuLoaded); } readBlob(cuLoaded); } function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; } }
ashx:
using Microsoft.VisualBasic.Devices; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web; using XLT.QC.Domain; using XLT.QC.Entity; namespace FTPupLoad.load { /// <summary> /// FileUpoload 的摘要说明 /// </summary> public class FileUpoload : IHttpHandler { private string basefilename = HttpContext.Current.Server.MapPath("../doc/allFile/"); private long totalCount = 0; public HttpRequest reqs; public void ProcessRequest(HttpContext context) { HttpRequest req = context.Request; string rquesttype = req.Form["rquesttype"]; var filename = req.Form["filename"];//文件的名称 switch (rquesttype) { case "chekcfile": chekcfile(req); break; case "uploadblob": uploadblob(req); break; case "finishupload": reqs = req; Task.Factory.StartNew(ThreadMethod);//解决线程并发 //finishupload(req); break; } } public void ThreadMethod() { while (true) { lock (typeof(FileUpoload)) { finishupload(reqs); Thread.Sleep(500); } } } /// <summary> /// 结束文件上传,修改上传后的名称 /// </summary> /// <param name="req"></param> public void finishupload(HttpRequest req) { string id = req.Form["id"]; string type = req.Form["type"]; //接收前端传递过来的参数 var md5value = req.Form["md5value"];//文件md5加密的字符串 var filename = req.Form["filename"];//文件的名称 var totalsize = req.Form["totalsize"];//文件的总大小 string fullname = basefilename + md5value + ".part";//上传的时候的名称 string okname = basefilename + md5value + ".ok"; var oldname = basefilename + filename; Computer MyComputer = new Computer(); try { //FileInfo okn = new FileInfo(okname); //if (!okn.Exists) //{ File.Create(okname); //} FileInfo fi = new FileInfo(oldname); if (fi.Exists) { fi.Delete(); } MyComputer.FileSystem.RenameFile(fullname, filename); } catch (Exception ex) { } finally { ArtificialDataTitleDomain art = new ArtificialDataTitleDomain(); ArtificialDataTitleEntity Inspect = new ArtificialDataTitleEntity(); TestingMachineTitleDomain tmt = new TestingMachineTitleDomain(); TestingMachineTitleEntity Repair = new TestingMachineTitleEntity(); if (type == "Inspect") { Inspect = art.FindByID(id); if (!string.IsNullOrWhiteSpace(Inspect.docUrl)) { Inspect.docUrl = Inspect.docUrl + filename + ","; } else { Inspect.docUrl = "allFile*" + filename + ","; } art.Update(Inspect); } else if (type == "Repair") { Repair = tmt.FindByID(id); if (!string.IsNullOrWhiteSpace(Repair.docUrl)) { Repair.docUrl = Repair.docUrl + filename + ","; } else { Repair.docUrl = "allFile*" + filename + ","; } tmt.Update(Repair); } var str = string.Format("{{"data":"ok"}}"); HttpContext.Current.Response.Write(str); } } /// <summary> /// 处理文件分块上传的数据 /// </summary> /// <param name="req"></param> public void uploadblob(HttpRequest req) { if (req.Files.Count <= 0) { HttpContext.Current.Response.Write("获取服务器上传文件失败"); return; } HttpPostedFile _file = req.Files[0]; //获取参数 string filename = req.Form["filename"]; string md5value = req.Form["md5value"]; var tempfilename = md5value + ".part"; //如果是int 类型当文件大的时候会出问题 最大也就是 1.9999999990686774G long loaded = Convert.ToInt64(req.Form["loaded"]); totalCount += loaded; string newname = basefilename + tempfilename; Stream stream = _file.InputStream; if (stream.Length <= 0) throw new Exception("接收的数据不能为空"); byte[] dataOne = new byte[stream.Length]; stream.Read(dataOne, 0, dataOne.Length); FileStream fs; try { fs = new FileStream(newname, FileMode.Append, FileAccess.Write, FileShare.Read, 1024); fs.Write(dataOne, 0, dataOne.Length); fs.Close(); } catch (Exception ex) { } finally { stream.Close(); //检查文件已经上传的大小是否等于文件的总大小 } HttpContext.Current.Response.Write("分段数据保存成功"); } /// <summary> /// 检查文件是否存在 /// </summary> /// <param name="req"></param> public void chekcfile(HttpRequest req) { var md5value = req.Form["md5value"];//得到前端传递过来的文件的mdf字符串 var path_ok = basefilename + md5value + ".ok"; var path_part = basefilename + md5value + ".part"; int flag = 0; string json = string.Empty; if (File.Exists(path_ok))//传完了 { flag = 2; json = string.Format("{{"flag":"{0}"}}", flag); } else if (File.Exists(path_part))//传了一部分 { flag = 1; var startindex = new FileInfo(path_part).Length.ToString(); json = string.Format("{{"flag":"{0}","startindex":"{1}"}}", flag, startindex); } else//新文件 { flag = 0; json = string.Format("{{"flag":"{0}","startindex":"0"}}", flag); } HttpContext.Current.Response.Write(json); } public bool IsReusable { get { return false; } } } }