asp.net c# 断点续传 下载 Accept-Ranges
转自:http://www.cnblogs.com/90nice/p/3489287.html
1.因为要下载大文件 需要断点续传,使用多线程 分段下载 效率比较高,节省资源。
发点牢骚:下载可以用多线程,如果是上传 我觉得没必要了。如果是普通用户(adsl) 上传速度只有50KB/s 据我所知100MB光纤 家庭用户下载理论值能达到12.5MB/S 但是上传目前却只有 256kb/s 这点速度够干啥的。希望以后 上传下载速度能一致。
下面是一个简单的例子:
服务端:
如果是分段下载 在http Header 头文件里 要有Range ,下面会有 客户端的例子。
var range = Request.Headers["Range"];
if (null == range)
{ //正常情况 200
Response.StatusCode = ;
Response.ContentType = "application/x-zip-compressed";
Response.AddHeader("Content-Disposition", "attachment;filename=" + fName);
FileStream fs = new FileStream(fUrl, FileMode.Open);
long len = fs.Length;
fs.Close();
fs.Dispose();
Response.AddHeader("Accept-Ranges", len.ToString());
Response.TransmitFile(fUrl);
}
else
{ //Accept - Range 情况
string[] re = range.Split('=');
string[] r = re[].Split('-');
long start = ;
long alength = ;
long fslength = ;
// 如果开始为空 从0开始取
if (string.IsNullOrEmpty(r[]))
start = ;
else
start = Convert.ToInt64(r[]);
//取文件总长度
FileStream fs = new FileStream(fUrl, FileMode.Open);
fslength = fs.Length;
fs.Close();
fs.Dispose();
// 字节长度
if (string.IsNullOrEmpty(r[]))
alength = fslength - start;
else
alength = Convert.ToInt64(r[]) - start;
Response.StatusCode = ; //分段下载状态
Response.ContentType = "application/x-zip-compressed";
Response.AddHeader("Content-Disposition", "attachment;filename=" + fName);
Response.AddHeader("Accept-Ranges", (alength - start).ToString());
Response.AddHeader("Content-Range", "bytes " + start + "-" + (start + alength) + "/" + fslength.ToString()); //Content-Range: bytes 100-200/1024 告诉客户端 本次请求的文件位置和总文件大小
// 文件路径 开始位置 取多少字节
Response.TransmitFile(fUrl, start, alength);
客户端 例子:
创建一个 http请求 并 写入请求的文件段
var request = (HttpWebRequest)WebRequest.Create("http://localhost:40337/PublicPage/ZrqPublicImg.zip");
request.AddRange(, );
try
{
//获取HTTP回应,注意HttpWebResponse继承自IDisposable
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode == HttpStatusCode.OK)
throw new Exception("文件不支持Range部分下载");
//设置接收信息的缓冲器
var bytes = new byte[];
//获取回应的Stream(字节流)
using (var stream = response.GetResponseStream())
{//FileMode.Append 我这里是从文件末尾处写入 如果是多线程 就要根据具体的请求的位置 写入文件
using (var outStream = new FileStream(@"D:\222.jpg", FileMode.Append, FileAccess.Write, FileShare.None))
{
const int bufferLen = ;
byte[] buffer = new byte[bufferLen];
int count = ;
while ((count = stream.Read(buffer, , bufferLen)) > )
{
outStream.Write(buffer, , count);
}
outStream.Close();
stream.Close();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("错误信息:{0}", ex.Message);
}
另附支持限速下载的方法(服务器代码):
/// <summary>
/// 输出硬盘文件,提供下载 支持大文件、续传、速度限制、资源占用小
/// </summary>
/// <param name="_Request">;Page.Request对象</param>
/// <param name="_Response">;Page.Response对象</param>
/// <param name="_fileName">下载文件名</param>
/// <param name="_fullPath">带文件名下载路径</param>
/// <param name="_speed">每秒允许下载的字节数</param>
/// <returns>返回是否成功</returns>
//---------------------------------------------------------------------
//调用:
// string FullPath=Server.MapPath("count.txt");
// ResponseFile(this.Request,this.Response,"count.txt",FullPath,100);
//---------------------------------------------------------------------
public static bool ResponseFile(HttpRequest _Request, HttpResponse _Response, string _fileName, string _fullPath, long _speed)
{
try
{
FileStream myFile = new FileStream(_fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
try
{
_Response.AddHeader("Accept-Ranges", "bytes");
_Response.Buffer = false; long fileLength = myFile.Length;
long startBytes = ;
int pack = ; //10K bytes
int sleep = (int)Math.Floor((double)( * pack / _speed)) + ; if (_Request.Headers["Range"] != null)
{
_Response.StatusCode = ;
string[] range = _Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[]);
}
_Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
if (startBytes != )
{
_Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - , fileLength));
} _Response.AddHeader("Connection", "Keep-Alive");
_Response.ContentType = "application/octet-stream";
_Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(_fileName, System.Text.Encoding.UTF8)); br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + ; for (int i = ; i < maxCount; i++)
{
if (_Response.IsClientConnected)
{
_Response.BinaryWrite(br.ReadBytes(pack));
Thread.Sleep(sleep);
}
else
{
i = maxCount;
}
}
}
catch
{
return false;
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
return false;
}
return true;
}
}
asp.net c# 断点续传 下载 Accept-Ranges的更多相关文章
- ASP.NET WebAPi之断点续传下载(上)
前言 之前一直感觉断点续传比较神秘,于是想去一探究竟,不知从何入手,以为就写写逻辑就行,结果搜索一番,还得了解相关http协议知识,又花了许久功夫去看http协议中有关断点续传知识,有时候发觉东西只有 ...
- ASP.NET WebAPi之断点续传下载(下)
前言 上一篇我们穿插了C#的内容,本篇我们继续来讲讲webapi中断点续传的其他情况以及利用webclient来实现断点续传,至此关于webapi断点续传下载以及上传内容都已经全部完结,一直嚷嚷着把S ...
- NET WebAPi之断点续传下载1
ASP.NET WebAPi之断点续传下载(上) 前言 之前一直感觉断点续传比较神秘,于是想去一探究竟,不知从何入手,以为就写写逻辑就行,结果搜索一番,还得了解相关http协议知识,又花了许久功夫 ...
- 发放春节福利,ASP.NET Core断点续传
ASP.NET Core断点续传 在ASP.NET WebAPi写过完整的断点续传文章,目前我对ASP.NET Core仅止于整体上会用,对于原理还未去深入学习,由于有园友想看断点续传在ASP.NET ...
- Android实现网络多线程断点续传下载(转)
本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...
- Android实现网络多线程断点续传下载
本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...
- Android网络多线程断点续传下载
本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...
- HTTP断点续传下载的原理
frombegintoend原文HTTP断点续传下载的原理 要实现断点续传下载文件,首先要了解断点续传的原理.断点续传其实就是在上一次下载断开的位置开始继续下载,HTTP协议中,可以在请求报文头中加入 ...
- php实现大文件断点续传下载实例
php实现大文件断点续传下载实例,看完你就知道超过100M以上的大文件如何断点传输了,这个功能还是比较经典实用的,毕竟大文件上传功能经常用得到. require_once('download.clas ...
随机推荐
- Git学习系列之Git产生的背景
不多说,直接上干货! 史上最浅显易懂的Git教程! 为什么要编写这个教程?因为我在学习Git的过程中,买过书,也在网上Google了一堆Git相关的文章和教程,但令人失望的是,这些教程不是难得令人发指 ...
- clojure学习笔记(一)
下载地址 需要安装xmind打开 http://pan.baidu.com/s/1dDxKj1B
- CentOS6.4 安装sftp
1.打开命令终端窗口,按以下步骤操作.使用ssh -V 命令来查看openssh的版本,版本必须大于4.8p1,低于的这个版本需要升级. [root@ecs-3c46 ~]# ssh -v OpenS ...
- JAVA源码之JDK(二)——Integer、Long、Double
这篇文章继续java.lang包下的源码学习,笔者也是找了几个比较常用的来阅读.下面针对Integer.Long.Double这样的基本类型的封装类,记录一些比较经典.常用的方法的学习心得,如toSt ...
- FocusBI: 使用Python爬虫为BI准备数据源(原创)
关注微信公众号:FocusBI 查看更多文章:加QQ群:808774277 获取学习资料和一起探讨问题. <商业智能教程>pdf下载地址 链接:https://pan.baidu.com/ ...
- viewport其实没那么难理解
在学习移动端布局的时候,你肯定听说过"viewport"这个词,然后去问度娘或谷歌.你会惊奇的发现,这个viewport不简单,居然有那么多兄弟——layout viewport. ...
- MySQL之函数
了解编程的人一般都会知道函数的重要性,丰富的函数有的时候可以给我们带来事半功倍的效果,在MySQL中提供了许多的内置函数,能够帮助开发人员编写简单快捷的SQL语句,除了这些内置的函数之外,用户也可以自 ...
- 记一次使用cmd执行java文件遇到的坑...包括“使用java命令运行class文件提示“错误:找不到或无法加载主类“的问题”
今天写了一个java文件,类似聊天软件的东西.在eclipse里输入输出显得没感觉,于是乎就准备在cmd里输入和显示输出.如下图,我准备运行的是ChatDemo.class文件.路径是:D:\work ...
- ajax实现菜单联动显示信息(当选择单位的时候,动态关联出人员信息)
在jsp页面中使用onchange属性调用下面的方法: 在script中写入: function fromid(){ var from_id = $("#from_id").val ...
- Docker安装和状态查询指令
1 .安装 Docker $ yum install -y docker-engine 2.启动docker $systemctl start docker.service 3.验证安装是否成功(有c ...