Bestcomy.net blog

Coding for funny
posts - 115, comments - 2725, trackbacks - 19, articles - 1

Asp.net(c#)实现多线程断点续传

Posted on 2004-08-10 16:50 bestcomy 阅读(24149) 评论(48)  编辑 收藏

以前一直错误的认为在ASP.NET中无法通过编程方式实现多线程断点续传,今天终于获得了这样一个解决方案,让我明白要学习的东西还很多
此解决方案基于其它解决方案及相关资料,根据我自己的理解改进.如有错漏,请尽管指出;如有其它更好的解决方案,请推荐一下,感谢先。

System.IO.Stream iStream = null;

            
// Buffer to read 10K bytes in chunk:
            byte[] buffer = new Byte[10240];

            
// Length of the file:
            int length;

            
// Total bytes to read:
            long dataToRead;

            
// Identify the file to download including its path.
            string filepath  = @"E:\software\SQL Server 2000 Personal Edition.ISO";

            
// Identify the file name.
            string  filename  = System.IO.Path.GetFileName(filepath);

            
try
            
{
                
// Open the file.
                iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, 
                    System.IO.FileAccess.Read,System.IO.FileShare.Read);
                Response.Clear();

                
// Total bytes to read:
                dataToRead = iStream.Length;

                
long p = 0;
                
if(Request.Headers["Range"]!=null)
                
{
                    Response.StatusCode 
= 206;
                    p 
= long.Parse( Request.Headers["Range"].Replace("bytes=","").Replace("-",""));
                }

                
if(p != 0)
                
{
                    Response.AddHeader(
"Content-Range","bytes " + p.ToString() + "-" + ((long)(dataToRead - 1)).ToString() + "/" + dataToRead.ToString());                    
                }

                Response.AddHeader(
"Content-Length",((long)(dataToRead-p)).ToString());
                Response.ContentType 
= "application/octet-stream";
                Response.AddHeader(
"Content-Disposition""attachment; filename=" + System.Web.HttpUtility.UrlEncode(Request.ContentEncoding.GetBytes(filename)));

                iStream.Position 
= p;
                dataToRead 
= dataToRead - p;
                
// Read the bytes.
                while (dataToRead > 0)
                
{
                    
// Verify that the client is connected.
                    if (Response.IsClientConnected) 
                    
{
                        
// Read the data in buffer.
                        length = iStream.Read(buffer, 010240);

                        
// Write the data to the current output stream.
                        Response.OutputStream.Write(buffer, 0, length);

                        
// Flush the data to the HTML output.
                        Response.Flush();

                        buffer
= new Byte[10240];
                        dataToRead 
= dataToRead - length;
                    }

                    
else
                    
{
                        
//prevent infinite loop if user disconnects
                        dataToRead = -1;
                    }

                }

            }

            
catch (Exception ex) 
            
{
                
// Trap the error, if any.
                Response.Write("Error : " + ex.Message);
            }

            
finally
            
{
                
if (iStream != null
                
{
                    
//Close the file.
                    iStream.Close();
                }
                   Response.End();
            }


本解决方案所参考的资料链接列表(在此对作者表示感谢):
http://blog.csdn.net/playyuer/archive/2004/08/02/58430.aspx
http://www.httpsniffer.com/http/1416.htm
http://support.microsoft.com/default.aspx?scid=kb;en-us;812406&Product=aspnet

更新:
        此解决方案已根据playyuer 提出的问题作了更新,另外在输出前调用了Response.Clear();方法。

Feedback

#1楼    回复  引用    

2004-08-10 16:55 by 宝玉 [未注册用户]
是不是要加到你上传控件中了?期待,呵呵

#2楼    回复  引用    

2004-08-10 17:01 by 宝玉 [未注册用户]
原来这里的“传”是“下载”而不是“上传”亚!

#3楼    回复  引用  查看    

2004-08-10 17:11 by bestcomy      
to 宝玉 
的确,这里的传是下载的意思:)

不过我考虑了一下,通过浏览器实现多线程断点上传的可能性不大。不过或许以后能发现什么解决方案呢:)
只有想不到,没有做不到。

#4楼    回复  引用    

2004-08-10 20:10 by playyuer [未注册用户]
http://support.microsoft.com/default.aspx?scid=kb;en-us;812406&Product=aspnet

这篇文章有一个狠大的问题!
没有这句话:
Response.End();
你下的文件总会 多几百个字节!
恰好是使 WebForm 的 HTML 源码!

WriteFile 同样也有该问题!
不信你就自己查查!

#5楼    回复  引用    

2004-08-10 20:16 by playyuer [未注册用户]
用 IE 应该比较困难!
文件域插不上手!

自己写程序发送 Http Request 还可以!

C# 写的 HttpRequsetResponse 类,异步、事件... 还热乎着呢! 
http://blog.csdn.net/playyuer/archive/2003/07/03/2856.aspx

#6楼    回复  引用    

2004-08-10 20:28 by playyuer [未注册用户]
除非你特殊支持!
用 域 发送 字节起点, 字节数!

不能用 IE! IE 只会傻乎乎的从头传!

#7楼    回复  引用  查看    

2004-08-10 21:38 by venjiang      
开源吧.

#8楼    回复  引用  查看    

2004-08-10 22:38 by bestcomy      
playyuer 批评的很有道理,感谢提点
不知道venjiang 说的“开源吧”是什么意思?这个本来就是贴出源代码的

#9楼    回复  引用  查看    

2004-08-11 17:58 by lion      
老干部最近找到工作了没?
头一次看到你在cnblogs里活动,可能是我不常来吧

#10楼    回复  引用    

2004-08-23 13:32 by nono [未注册用户]
very good!!!
  And thanks!

#11楼    回复  引用    

2004-08-23 13:42 by nono [未注册用户]
  看看修改<AddHeader>可不可以上传?

#12楼    回复  引用    

2004-08-25 10:00 by buaaytt [未注册用户]
拜托,哪里体现了多线程啊?

#13楼    回复  引用  查看    

2004-08-31 12:55 by bestcomy      
to  nono 
没有试过,应该没有可能。

to buaaytt 
用flashget下载就可以看到

#14楼    回复  引用    

2004-09-13 13:41 by kevin_Y [未注册用户]
能否实现单线程呢?

如何限制用户用能使用一个线程下载呢?

#15楼    回复  引用  查看    

2004-09-13 18:35 by bestcomy      
单线程
http://support.microsoft.com/default.aspx?scid=kb;en-us;812406&Product=aspnet

#16楼    回复  引用    

2004-09-15 14:05 by kevin_Y [未注册用户]
单线程 
http://support.microsoft.com/default.aspx?scid=kb;en-us;812406&Product=aspnet 

但不支持断点。

可能是我上一个没说清楚。

我希望的是单线程但支持断点

#17楼    回复  引用    

2004-10-16 11:00 by kevin_Y [未注册用户]
错误发生在这一行
Response.AddHeader("Content-Length",((long)(dataToRead-p)).ToString());

提供几对当时两变量的值给你:
1.
<dataToRead>12549594</dataToRead>
<p>405504012549593</p>

2.

<dataToRead>262172</dataToRead>
<p>262144262171</p>

3.

<dataToRead>262172</dataToRead>
<p>262144262171</p>

且我尝试了以下代码:
long temp =0;
temp = dataToRead-p;
Response.AddHeader("Content-Length",temp.ToString());//报这行出错.

错误信息:值对于 Int32 太大或太小。

#18楼    回复  引用    

2005-01-26 16:51 by qianwt [未注册用户]
是可以实现断点续传了,可假如文件名是中文的话,用flashget下载的话,文件名就编码过了,直接在IE里面保存就是好的,这个问题怎么解决呀。

#19楼    回复  引用    

2005-02-03 10:38 by hozi [未注册用户]
正在下载的时候点击取消,页面就会出现死循环,谁知道该怎样解决?? 谢谢!

#20楼    回复  引用    

2005-04-15 19:27 by www.52mobiles.com [未注册用户]
上传一样可以实现哦,可以在google 搜索 纵横HTTP文件上传组件

#21楼 [楼主]   回复  引用    

2005-04-15 20:44 by bestcomy [未注册用户]
纵横HTTP文件上传组件 需要客户端安装,这就是它的缺点所在。

#22楼    回复  引用    

2005-06-08 13:23 by 游客 [未注册用户]
这样文件下载到什么地方了??

#23楼    回复  引用    

2005-06-20 11:43 by dujid [未注册用户]
只用IE的多线程上传别考虑了,目前看来只要国际组织不改变 rfc 规定,IE永远不可能支持多线程文件上传,不管是IE,其他符合 rfc1867 的浏览器都不可能实现。

也许我在阅读中还有疏漏,大家可以去看看 rfc 规定,地址:
http://www.faqs.org/rfcs/rfc1867.html

唯一提到分组数据的也只是下载。

#24楼    回复  引用    

2005-07-20 10:57 by yyq [未注册用户]
为什么我用flashget下载的时候只能是单线程啊?直接用IE下的时候,也没有断点续传,都是从头下的。

#25楼    回复  引用  查看    

2005-10-04 09:52 by Tmouse      
请教:如何才能断点续点网络上的文件?您这个是运行在服务器段,下载的也是服务器上的文件。

#26楼    回复  引用    

2005-10-15 17:42 by haoxue [未注册用户]
在下载的过程中,如果中断下载,再继续下载,将出现页面无响应的情况。根据调试发现,在中断下载的过程中没有执行
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
Response.End();
}
直到全部的页面退出后才执行。请问该出何解决这个问题

#27楼 [楼主]   回复  引用  查看    

2005-10-15 19:22 by bestcomy      
调试一下 Response.IsClientConnected 是否可以执行,如果可以执行的话就在else 中执行关闭文件流

#28楼    回复  引用    

2005-10-28 13:08 by xxx [未注册用户]
no right

#29楼    回复  引用    

2005-10-28 13:09 by xxx [未注册用户]
bu xing

#30楼 [楼主]   回复  引用  查看    

2005-10-28 14:28 by bestcomy      
能否详细描述出现这种情况的操作过程
页面无响应是指那个页面?

#31楼    回复  引用    

2006-03-25 17:29 by awar [未注册用户]
好像不能下载远程文件?你的例子给的是本地硬盘文件,我试了一下,本地和局域网文件都没问题,下载互联网上文件时出现“Error : URI formats are not supported.”错误。不知何故?

#32楼    回复  引用    

2006-05-27 12:22 by teamming [未注册用户]
请问你是怎么实现多线程的?我根本没有发现有多线程的痕迹~!!

#33楼    回复  引用    

2006-07-05 22:02 by MoonPan [未注册用户]
好东西,正好用上,谢谢,我要把她收集起来.

#34楼    回复  引用    

2006-07-06 23:51 by fady64@msn.com [未注册用户]
Bestcomy,

Your example works great. But my in my case I am reading the file from a URL rather than from the file system. I tried using a MemoryStream instead of a file stream, but it is not working.

For getting the file I am using:
Request = (HttpWebRequest) System.Net.WebRequest.Create(Url);

Then I am using ASCIIEncoding to transfrom the string into byte[]/

Fady

#35楼    回复  引用    

2006-09-06 10:23 by 路过 [未注册用户]
这是一个错误的例子.只能用于demo,不能真正应用.
一般来说需要断点续传,来文件基本上都是很大的.
Response.OutputStream.Write(buffer, 0, length);
会把输出内容先发给asp.net isapi,然后由它一起发送给iis的isapi.简单说会把一个大文件缓存在内存中最后一下子发送给客户端.如果文件很大内存一会就吃光了.而如果同时有多个客户端下载的时候系统非常容易当机.

所以ASP.NET从1.1开始就提供TransmitFile来传输文件给客户端.它能不经过IIS的isapi而在asp.net的isapi层直接和客户端打交道,简单说可以直接实时地将内容写到客户端而不会缓存在内存中.它接收文件而不是byte[],所以在它上面无法实现断点续传.

要想真正实现ASP.NET的断点续传,除非你能用将Write方法绕过iis的ISAPI,直接向用户发送.否则系统要不了多久就会当掉.不要以为在你自己的机器上测试就可以了,你自己一个客户端下载时机器最多也就是把一个文件全部缓存到内存中.
想想在多用户请求时会是什么样子.

#36楼    回复  引用    

2006-09-27 15:16 by meng[匿名] [未注册用户]
非常感谢

#37楼    回复  引用    

2007-02-07 22:00 by zzzzz [未注册用户]
的确是不能多用户使用,我自己测试,用下载软件,两个任务,才不到20个线程,我在下载软件中限制了下载速度,不到100K/S,但是asp.net却死掉了!!!!包括其他虚拟目录、甚至其他网站,只要是aspx的全部死掉,但是cpu,内存不占多少,停止下载后又回复了!

#38楼    回复  引用    

2007-03-16 09:38 by wow [未注册用户]
www.tudou.com www.tvix.cn这些视频网站是如何上传视频的?不是用这样的原理吧?

#39楼    回复  引用    

2007-06-15 10:18 by tooth [未注册用户]
是我比较愚钝,我也没有看到如何体现出来多线程。
你不会是这个方法,然后通过其它线程来调用吧?

#40楼    回复  引用    

2007-06-22 09:36 by aNUiz [未注册用户]
"所以ASP.NET从1.1开始就提供TransmitFile来传输文件给客户端."
挑个小刺,我刚才看MSDN的时候,发现是从2.0才开始支持的,不知道谁错了...

#41楼    回复  引用    

2007-07-03 13:35 by 英雄浪子 [未注册用户]
这个到底能不能实现断点上传功能?

#42楼 [楼主]   回复  引用  查看    

2007-07-03 14:15 by bestcomy      
@英雄浪子
这里是说下载可以断点续传,没说上传的事

#43楼    回复  引用    

2007-12-13 17:42 by Leon。Lei [未注册用户]
很大一个问题:这个只是一个服务端程序,并不支持客户端上传

#44楼    回复  引用    

2008-03-05 11:24 by 小妮子 [未注册用户]
请问你是怎么实现多线程的?我根本没有发现有多线程的痕迹~!!晕死,原来是下载,还以为断网了。。。。

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2004-08-11 09:28 编辑过


相关链接: