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, 0, 10240);

// 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
更新:
此解决方案已根据 提出的问题作了更新,另外在输出前调用了Response.Clear();方法。
Feedback
to 宝玉
的确,这里的传是下载的意思:)
不过我考虑了一下,通过浏览器实现多线程断点上传的可能性不大。不过或许以后能发现什么解决方案呢:)
只有想不到,没有做不到。
http://support.microsoft.com/default.aspx?scid=kb;en-us;812406&Product=aspnet
这篇文章有一个狠大的问题!
没有这句话:
Response.End();
你下的文件总会 多几百个字节!
恰好是使 WebForm 的 HTML 源码!
WriteFile 同样也有该问题!
不信你就自己查查!
用 IE 应该比较困难!
文件域插不上手!
自己写程序发送 Http Request 还可以!
C# 写的 HttpRequsetResponse 类,异步、事件... 还热乎着呢!
http://blog.csdn.net/playyuer/archive/2003/07/03/2856.aspx
除非你特殊支持!
用 域 发送 字节起点, 字节数!
不能用 IE! IE 只会傻乎乎的从头传!
playyuer 批评的很有道理,感谢提点
不知道venjiang 说的“开源吧”是什么意思?这个本来就是贴出源代码的
老干部最近找到工作了没?
头一次看到你在cnblogs里活动,可能是我不常来吧
to nono
没有试过,应该没有可能。
to buaaytt
用flashget下载就可以看到
能否实现单线程呢?
如何限制用户用能使用一个线程下载呢?
错误发生在这一行
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 太大或太小。
是可以实现断点续传了,可假如文件名是中文的话,用flashget下载的话,文件名就编码过了,直接在IE里面保存就是好的,这个问题怎么解决呀。
正在下载的时候点击取消,页面就会出现死循环,谁知道该怎样解决?? 谢谢!
上传一样可以实现哦,可以在google 搜索 纵横HTTP文件上传组件
纵横HTTP文件上传组件 需要客户端安装,这就是它的缺点所在。
只用IE的多线程上传别考虑了,目前看来只要国际组织不改变 rfc 规定,IE永远不可能支持多线程文件上传,不管是IE,其他符合 rfc1867 的浏览器都不可能实现。
也许我在阅读中还有疏漏,大家可以去看看 rfc 规定,地址:
http://www.faqs.org/rfcs/rfc1867.html
唯一提到分组数据的也只是下载。
为什么我用flashget下载的时候只能是单线程啊?直接用IE下的时候,也没有断点续传,都是从头下的。
请教:如何才能断点续点网络上的文件?您这个是运行在服务器段,下载的也是服务器上的文件。
在下载的过程中,如果中断下载,再继续下载,将出现页面无响应的情况。根据调试发现,在中断下载的过程中没有执行
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
Response.End();
}
直到全部的页面退出后才执行。请问该出何解决这个问题
调试一下 Response.IsClientConnected 是否可以执行,如果可以执行的话就在else 中执行关闭文件流
能否详细描述出现这种情况的操作过程
页面无响应是指那个页面?
好像不能下载远程文件?你的例子给的是本地硬盘文件,我试了一下,本地和局域网文件都没问题,下载互联网上文件时出现“Error : URI formats are not supported.”错误。不知何故?
请问你是怎么实现多线程的?我根本没有发现有多线程的痕迹~!!
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
这是一个错误的例子.只能用于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,直接向用户发送.否则系统要不了多久就会当掉.不要以为在你自己的机器上测试就可以了,你自己一个客户端下载时机器最多也就是把一个文件全部缓存到内存中.
想想在多用户请求时会是什么样子.
的确是不能多用户使用,我自己测试,用下载软件,两个任务,才不到20个线程,我在下载软件中限制了下载速度,不到100K/S,但是asp.net却死掉了!!!!包括其他虚拟目录、甚至其他网站,只要是aspx的全部死掉,但是cpu,内存不占多少,停止下载后又回复了!
www.tudou.com www.tvix.cn这些视频网站是如何上传视频的?不是用这样的原理吧?
是我比较愚钝,我也没有看到如何体现出来多线程。
你不会是这个方法,然后通过其它线程来调用吧?
"所以ASP.NET从1.1开始就提供TransmitFile来传输文件给客户端."
挑个小刺,我刚才看MSDN的时候,发现是从2.0才开始支持的,不知道谁错了...
@英雄浪子
这里是说下载可以断点续传,没说上传的事
很大一个问题:这个只是一个服务端程序,并不支持客户端上传
请问你是怎么实现多线程的?我根本没有发现有多线程的痕迹~!!晕死,原来是下载,还以为断网了。。。。