收藏 分享(赏)

.net文件下载所有方法.doc

上传人:11xg27ws 文档编号:7806607 上传时间:2019-05-26 格式:DOC 页数:12 大小:71.50KB
下载 相关 举报
.net文件下载所有方法.doc_第1页
第1页 / 共12页
.net文件下载所有方法.doc_第2页
第2页 / 共12页
.net文件下载所有方法.doc_第3页
第3页 / 共12页
.net文件下载所有方法.doc_第4页
第4页 / 共12页
.net文件下载所有方法.doc_第5页
第5页 / 共12页
点击查看更多>>
资源描述

1、 URL 方式直接下载,优点是:占用服务器资源少,速度快;缺点是: 不能准确计量下载次数,无法防止盗链,保存在数据库中的文件无法下载,常见格式的文件如.html 直接在浏览器中打开,不能直接下载。二进制数据流输出方式,优点是:准确计量下载次数、能防盗链、所有文件格式都能直接下载而不是打开、保存在数据库中等非文件数据能以文件方式下载等;缺点是占用服务器资源多。 大文件下载原理是把文件切成小段数据流下载public partial class FileDownLoad : System.Web.UI.Page /提供下载的文件,不编码的话文件名会乱码 private string fileName

2、 = HttpContext.Current.Server.UrlEncode(“规范.rar“); private string filePath = HttpContext.Current.Server.MapPath(“规范.rar“); /使用 TransmifFile 下载文件 /*6 微软为 Response 对象提供了一个新的方法 TransmitFile 来解决使用Response.BinaryWrite7 下载超过 400mb 的文件时导致 Aspnet_wp.exe 进程回收而无法成功下载的问题。8 代码如下:9 */protected void btnDL1_Click(

3、object sender, EventArgs e) FileInfo info = new FileInfo(filePath); long fileSize = info.Length; Response.Clear(); Response.ContentType = “application/x-zip-compressed“; Response.AddHeader(“Content-Disposition“, “attachment;filename=“+ fileName); /不指明 Content-Length 用 Flush 的话不会显示下载进度 Response.AddHe

4、ader(“Content-Length“, fileSize.ToString(); Response.TransmitFile(filePath, 0, fileSize); /Response.TransmitFile(filename);Response.Flush(); Response.Close(); /使用 WriteFile 下载文件 protected void btnDL2_Click(object sender, EventArgs e) FileInfo info = new FileInfo(filePath); long fileSize = info.Lengt

5、h; Response.Clear(); Response.ContentType = “application/octet-stream“; Response.AddHeader(“Content-Disposition“, “attachement;filename=“ + fileName); /指定文件大小 Response.AddHeader(“Content-Length“, fileSize.ToString(); Response.WriteFile(filePath, 0, fileSize); Response.Flush(); Response.Close(); /使用

6、OutputStream.Write 分块下载文件 protected void btnDL3_Click(object sender, EventArgs e) /指定块大小 long chunkSize = 102400; /建立一个 100K 的缓冲区 byte buffer = new bytechunkSize; /已读的字节数 long dataToRead = 0; FileStream stream = null; try /打开文件 stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileSh

7、are.Read); dataToRead = stream.Length; /添加 Http 头 Response.ContentType = “application/octet-stream“; Response.AddHeader(“Content-Disposition“, “attachement;filename=“ + fileName); Response.AddHeader(“Content-Length“, dataToRead.ToString(); while (dataToRead 0) if (Response.IsClientConnected) int len

8、gth = stream.Read(buffer, 0, Convert.ToInt32(chunkSize); Response.OutputStream.Write(buffer, 0, length); Response.Flush(); buffer = new Byte10000; dataToRead -= length; else /防止 client 失去连接 dataToRead = -1; catch (Exception ex) Response.Write(“Error:“ + ex.Message); finally if (stream != null) strea

9、m.Close(); Response.Close(); /使用 BinaryWrite 下载文件,大文件效率不行 protected void btnDL4_Click(object sender, EventArgs e) FileStream stream = null; try /读文件,大文件一次读入会占用大量内存 stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); byte bytes = new bytestream.Length; stream.Read(bytes

10、, 0, bytes.Length); stream.Close(); /添加 Http 头 Response.ContentType = “application/octet-stream“; Response.AddHeader(“Content-Disposition“, “attachement;filename=“ + fileName); Response.AddHeader(“Content-Length“, bytes.Length.ToString(); Response.BinaryWrite(bytes); Response.Flush(); catch (Excepti

11、on ex) Response.Write(“Error:“ + ex.Message); finally if (stream != null) stream.Close(); Response.Close(); /使用 BinaryWrite 分块下载文件 protected void btnDL5_Click(object sender, EventArgs e) /指定区块和缓冲区 long chunkSize = 102400; byte buffer = new bytechunkSize; FileStream stream = null; long dataToRead = 0

12、; try stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); dataToRead = stream.Length; /添加 Http 头 Response.ContentType = “application/octet-stream“; Response.AddHeader(“Content-Disposition“, “attachement;filename=“ + fileName); Response.AddHeader(“Content-Length“, dataT

13、oRead.ToString(); while (dataToRead 0) if (Response.IsClientConnected) int length = stream.Read(buffer, 0, Convert.ToInt32(chunkSize); Response.BinaryWrite(buffer); Response.Flush(); Response.Clear(); dataToRead -= length; else dataToRead = -1; catch(Exception ex) Response.Write(“Error:“ + ex.Messag

14、e); finally if (stream != null) stream.Close(); Response.Close(); 以上除了第四种不推荐以外,其他的都可以,但是个人感觉分块下载的要好一点。没有仔细测试,所以可能有问题。 /中文标题转换if (browser.Contains(“FIREFOX“) = true)outputFileName = Path.GetFileName(photo.FilePath);elseoutputFileName = HttpUtility.UrlEncode(Path.GetFileName(photo.FilePath);注意:对于中文文件名

15、要编码才能正确显示。对于长中文文件名(UTF8 编码后大于 153字节的中文)即使编码了,还是有问题的,大家可以参考下面的文章。 关于中文文件下载的问题,网上的咨询和答疑已经很多,我原来处理下载的代码如下: response.setHeader(“Content-Disposition“, “attachment; filename=“ + .URLEncoder.encode(fileName, “UTF-8“); 下载的程序里有了这句,一般在 IE6 的下载提示框上将正确显示文件的名字,无论是简体中文,还是日文。不过当时确实没有仔细测试文件名很长的中文文件名。先如今经过仔细测试,发现文字只

16、要超过 17 个字,就不能下载了。经过好一番 google 和反复测试,总算对这个问题有了系统的认识,分列如下: 一. 通过我原来的方式,也就是先用 URLEncoder 编码,当中文文字超过 17 个时,IE6 无法下载文件。这是 IE 的 bug,参见微软的知识库文章 KB816868 。原因可能是因为ie 在处理 Response Header 的时候,对 header 的长度限制在 150 字节左右。而一个汉字编码成 UTF-8 是 9 个字节,那么 17 个字便是 153 个字节,所以便会报错。微软提供了一个补丁,可以从 这里 下载。这个补丁需要先安装 ie6 sp1。因为我平时勤打

17、补丁,我的 IE6 版本号是 6.0.2800.1106.xpsp2_xxxxx。所以我可能已经安装过了补丁,从而可以下载,但仍然出现文件名被截断的现象。微软让我们等待 IE 下一个 service pack的发布。我今天也上网看到了好消息,迫于 firefox 的压力,IE7 可能在年中发布。另外,Firefox 不支持这样的方式,将把编码后的%xx%xx 直接作为文件名显示。 二. 我尝试使用 javamail 的 MimeUtility.encode()方法来编码文件名,也就是编码成 =?gb2312?B?xxxxxxxx?= 这样的形式,并从 RFC1522 中找到对应的标准支持。不过

18、很遗憾,IE6 并不支持这一个标准。我试了一下, Firefox 是支持的。 三. 按网上很多人提供的解决方案:将文件名编码成 ISO8859-1 似乎是有效的解决方案,代码如下: response.setHeader( “Content-Disposition“, “attachment;filename=“ + new String( fileName.getBytes(“gb2312“), “ISO8859-1“ ) ); 在确保附件文件名都是简体中文字的情况下,那么这个办法确实是最有效的,不用让客户逐个的升级 IE。如果台湾同胞用,把 gb2312 改成 big5 就行。但现在的系统通

19、常都加入了国际化的支持,普遍使用 UTF-8。如果文件名中又有简体中文字,又有繁体中文,还有日文。那么乱码便产生了。另外,在我的电脑上 Firefox(v1.0-en)下载也是乱码。 折中考虑,我结合了一、三的方式,代码片断如下: 复制代码 代码如下:String fileName = URLEncoder.encode(atta.getFileName(), “UTF-8“); /* * see http:/ */ if (fileName.length() 150) String guessCharset = xxxx /*根据 request 的 locale 得出可能的编码,中文操作系

20、统通常是 gb2312*/ fileName = new String(atta.getFileName().getBytes(guessCharset), “ISO8859-1“); response.setHeader(“Content-Disposition“, “attachment; filename=“ + fileName); 暂且不考虑 Firefox 是因为它目前似乎还没有有力侵食到 IE 的企业用户市场。影响客户买单的常常是进度,而不是兼容度。/ / 下载文件,支持大文件、续传、速度限制。支持续传的响应头Accept-Ranges、ETag,请求头Range 。/ Acce

21、pt-Ranges:响应头,向客户端指明,此进程支持可恢复下载.实现后台智能传输服务(BITS),值为:bytes;/ ETag:响应头,用于对客户端的初始(200)响应,以及来自客户端的恢复请求,/ 必须为每个文件提供一个唯一的ETag值(可由文件名和文件最后被修改的日期组成),这使客户端软件能够验证它们已经下载的字节块是否仍然是最新的。/ Range:续传的起始位置,即已经下载到客户端的字节数,值如:bytes=1474560- 。/ 另外:UrlEncode编码后会把文件名中的空格转换中+(+转换为%2b),但是浏览器是不能理解加号为空格的,所以在浏览器下载得到的文件,空格就变成了加号;

22、/ 解决办法:UrlEncode 之后, 将 “+“ 替换成 “%20“,因为浏览器将%20转换为空格/ / 当前请求的HttpContext/ 下载文件的物理路径,含路径、文件名/ 下载速度:每秒允许下载的字节数/ true下载成功,false下载失败public static bool DownloadFile(HttpContext httpContext, string filePath, long speed)bool ret = true;try/-验证:HttpMethod,请求的文件是否存在switch (httpContext.Request.HttpMethod.ToUpp

23、er() /目前只支持GET和HEAD方法case “GET“:case “HEAD“:break;default:httpContext.Response.StatusCode = 501;return false;/ if (!File.Exists(filePath)/ httpContext.Response.StatusCode = 404;/ return false;/ /定义局部变量long startBytes = 0;int packSize = 1024 * 10; /分块读取,每块10K bytesstring fileName = Path.GetFileName(f

24、ilePath);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.Ge

25、tLastWriteTimeUtc(filePath).ToString(“r“);string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + lastUpdateTiemStr;/便于恢复下载时提取请求头;/ -验证:文件是否太大,是否是续传,且在上次被请求的日期之后是否被修改过-if (myFile.Length Int32.MaxValue)/-文件太大了-httpContext.Response.StatusCode = 413;/请求实体太大return false;if (httpContext.Request.He

26、aders“If-Range“ != null)/对应响应头ETag:文件名+文件最后修改时间/-上次被请求的日期之后被修改过-if (httpContext.Request.Headers“If-Range“.Replace(“, “) != eTag)/文件修改过httpContext.Response.StatusCode = 412;/预处理失败return false;try/ -添加重要响应头、解析请求头、相关验证-httpContext.Response.Clear();httpContext.Response.Buffer = false;/httpContext.Respon

27、se.AddHeader(“Content-MD5“, GetMD5Hash(myFile);/用于验证文件httpContext.Response.AddHeader(“Accept-Ranges“, “bytes“);/重要:续传必须httpContext.Response.AppendHeader(“ETag“, “ + eTag + “);/重要:续传必须httpContext.Response.AppendHeader(“Last-Modified“, lastUpdateTiemStr);/把最后修改日期写入响应 httpContext.Response.ContentType =

28、 “application/octet-stream“;/MIME类型:匹配任意文件类型httpContext.Response.AddHeader(“Content-Disposition“, “attachment;filename=“ + HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace(“+“, “%20“);httpContext.Response.AddHeader(“Content-Length“, (fileLength - startBytes).ToString();httpContext.Response.Add

29、Header(“Connection“, “Keep-Alive“);httpContext.Response.ContentEncoding = Encoding.UTF8;if (httpContext.Request.Headers“Range“ != null)/-如果是续传请求,则获取续传的起始位置,即已经下载到客户端的字节数-httpContext.Response.StatusCode = 206;/重要:续传必须,表示局部范围响应。初始下载时默认为200string range = httpContext.Request.Headers“Range“.Split(new cha

30、r =, - );/“bytes=1474560-“startBytes = Convert.ToInt64(range1);/已经下载的字节数,即本次下载的开始位置 if (startBytes = fileLength)/无效的起始位置return false;if (startBytes 0)/-如果是续传请求,告诉客户端本次的开始字节数,总长度,以便客户端将续传数据追加到startBytes位置后-httpContext.Response.AddHeader(“Content-Range“, string.Format(“ bytes 0-1/2“, startBytes, fileL

31、ength - 1, fileLength);/ -向客户端发送数据块-br.BaseStream.Seek(startBytes, SeekOrigin.Begin);int maxCount = (int)Math.Ceiling(fileLength - startBytes + 0.0) / packSize);/分块下载,剩余部分可分成的块数for (int i = 0; i 1) System.Threading.Thread.Sleep(sleep);catchret = false;finallybr.Close();myFile.Close();catchret = fals

32、e;return ret;/* 哈希函数将任意长度的二进制字符串映射为固定长度的小型二进制字符串。加密哈希函数有这样一个属性:在计算上不大可能找到散列为相同的值的两个不同的输入;也就是说,两组数据的哈希值仅在对应的数据也匹配时才会匹配。数据的少量更改会在哈希值中产生不可预知的大量更改。 MD5 算法的哈希值大小为 128 位。 MD5 类的 ComputeHash 方法将哈希作为 16 字节的数组返回。请注意,某些 MD5 实现会生成 32 字符的十六进制格式哈希。若要与此类实现进行互操作,请将 ComputeHash 方法的返回值格式化为十六进制值。 */ / / 获取输入流的由 MD5 计

33、算的 Hash 值,不可逆转 / / public static string GetMD5Hash(Stream inputStream) / Create a new instance of the MD5CryptoServiceProvider object. MD5 md5Hasher = MD5.Create();/不可逆转 byte data = md5Hasher.ComputeHash(inputStream); StringBuilder sb = new StringBuilder(); for (int i = 0; i / 验证输入流由 MD5 计算的 Hash 值 / / / / public static bool VerifyMD5Hash(Stream inputStream, string hash) string hashOfInputStream = GetMD5Hash(inputStream); StringComparer comparer = StringComparer.OrdinalIgnoreCase; if (comparer.Compare(hashOfInputStream, hash) = 0) return true; else return false;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报