/// <summary> /// 打包下载 /// </summary> /// <param name="packFolderPath">需要打包的文件夹所在路径</param> /// <param name="fileNames">需要打包的文件集合(文件名)</param> /// <param name="zipFileName">打包后显示的文件名</param> public static void FilePackDownload(string packFolderPath, List <string> fileNames, string zipFileName) { using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(System.Text.Encoding.Default))//解决中文乱码问题 { HttpContext httpContext = HttpContext.Current; httpContext.Response.Clear(); httpContext.Response.ContentType = "application/zip"; //兼容火狐和IE11的浏览器下载 string packFileName = ""; if (httpContext.Request.Headers["USER-AGENT"].IndexOf("MSIE") < 0 && httpContext.Request.Headers["USER-AGENT"].IndexOf("like Gecko") < 0) { packFileName = "=?UTF-8?B?" + ALEncrypt.Base64EnCode(zipFileName) + "?="; } else { packFileName = HttpUtility.UrlEncode(zipFileName, Encoding.UTF8); } httpContext.Response.AddHeader("content-disposition", "filename=" + packFileName); zip.AddDirectory(packFolderPath); foreach (string item in fileNames) { try { zip.AddFile(item); } catch (Exception err) { ALMessage.RegMsg("打包下载失败,具体原因:" + err.Message); } } zip.Save(httpContext.Response.OutputStream); } }
/// <summary> /// 文件下载 /// </summary> /// <param name="filePath">所需下载文件的绝对路径</param> /// <param name="speed">限制速度以Byte为单位,若限制为200KB的下载速度则为1024 * 200</param> public static void FileDownload(string filePath, long speed, string downloadFileName, string mime) { HttpContext httpContext = HttpContext.Current; try { //验证:HttpMethod,为防止回传下载页面变成空白.只允许get下载 switch (httpContext.Request.HttpMethod.ToUpper()) { //目前只支持GET和HEAD方法 case "GET": case "HEAD": break; default: httpContext.Response.StatusCode = 501; return; } //验证:请求的文件是否存在 if (!System.IO.File.Exists(filePath)) { httpContext.Response.StatusCode = 404; return; } //定义局部变量 long startBytes = 0; int packSize = 1024 * 10; //分块读取,每块10K bytes string fileName = downloadFileName; if (string.IsNullOrEmpty(fileName)) { fileName = Path.GetFileName(filePath); } FileStream myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); BinaryReader br = new BinaryReader(myFile); long fileLength = myFile.Length; int sleep = (int)Math.Ceiling(1000.0 * packSize / speed); //毫秒数:读取下一数据块的时间间隔 string lastUpdateTiemStr = System.IO.File.GetLastWriteTimeUtc(filePath).ToString("r"); string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + lastUpdateTiemStr; //便于恢复下载时提取请求头; //验证:文件是否太大(2G) if (myFile.Length > Int32.MaxValue) { httpContext.Response.StatusCode = 413;//请求实体太大 return; } //对应响应头ETag:文件名+文件最后修改时间 if (httpContext.Request.Headers["If-Range"] != null) { //----------上次被请求的日期之后被修改过-------------- if (httpContext.Request.Headers["If-Range"].Replace("\"", "") != eTag) { //文件修改过 httpContext.Response.StatusCode = 412;//预处理失败 return; } } try { //添加重要响应头、解析请求头、相关验证 httpContext.Response.Clear(); httpContext.Response.Buffer = false; httpContext.Response.AddHeader("Content-MD5", ALEncrypt.Md5(myFile.ToString())); //用于验证文件 httpContext.Response.AddHeader("Accept-Ranges", "bytes"); //重要:续传必须 httpContext.Response.AppendHeader("ETag", "\"" + eTag + "\""); //重要:续传必须 httpContext.Response.AppendHeader("Last-Modified", lastUpdateTiemStr); //把最后修改日期写入响应 if (string.IsNullOrEmpty(mime)) { httpContext.Response.ContentType = "application/octet-stream";//MIME类型:匹配任意文件类型 } else { httpContext.Response.ContentType = mime; } if (httpContext.Request.Headers["USER-AGENT"].IndexOf("MSIE") < 0 && httpContext.Request.Headers["USER-AGENT"].IndexOf("like Gecko") < 0) { fileName = "=?UTF-8?B?" + ALEncrypt.Base64EnCode(fileName) + "?="; } else { fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", "%20"); } httpContext.Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName); httpContext.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString()); httpContext.Response.AddHeader("Connection", "Keep-Alive"); httpContext.Response.ContentEncoding = Encoding.UTF8; if (httpContext.Request.Headers["Range"] != null) { //------如果是续传请求,则获取续传的起始位置,即已经下载到客户端的字节数------ httpContext.Response.StatusCode = 206; //重要:续传必须,表示局部范围响应。初始下载时默认为200 string[] range = httpContext.Request.Headers["Range"].Split(new char[] { '=', '-' }); //"bytes=1474560-" startBytes = Convert.ToInt64(range[1]); //已经下载的字节数,即本次下载的开始位置 if (startBytes < 0 || startBytes >= fileLength) { return; } } //如果是续传请求,告诉客户端本次的开始字节数,总长度,以便客户端将续传数据追加到startBytes位置后 if (startBytes > 0) { httpContext.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength)); } //向客户端发送数据块 br.BaseStream.Seek(startBytes, SeekOrigin.Begin); //分块下载,剩余部分可分成的块数 int maxCount = (int)Math.Ceiling((fileLength - startBytes + 0.0) / packSize); //客户端未中断连接,并且数据没有传输完.则一直传输 for (int i = 0; i < maxCount && httpContext.Response.IsClientConnected; i++) { httpContext.Response.BinaryWrite(br.ReadBytes(packSize)); httpContext.Response.Flush(); if (sleep > 1) { Thread.Sleep(sleep); } } } catch (Exception ex) { throw ex; } finally { br.Close(); myFile.Close(); } } catch (Exception ex) { throw ex; } }