.net网站的文件上传读取进度条和断点下载
文件上传到服务器时的进度读取
UpfileResult result = new UpfileResult();
try
{
//直接使用request.Files读取,是无法计算进度的。需要主动操作文件流的读取,同时计算上传进度
IServiceProvider provider = HttpContext.Current;
HttpWorkerRequest request = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest)); // 获取请求正文的大小
long length = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
CheckFileSize(length, upfileConfig); int bytesRead = 0; // 已读数据大小
int readSize; // 当前读取的块的大小
int packSize = 1024 * 10;
byte[] buffer;
byte[] tempBuff;
if (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded())
{
buffer = new byte[length]; //http请求正文已被读取的部分
tempBuff = request.GetPreloadedEntityBody();
// 将已读取数据复制过来
Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, tempBuff.Length); // 开始记录已读取大小
bytesRead = tempBuff.Length; //计算当前上传文件的百分比
long percent = (long)bytesRead * 100 / length;
SetPercent(SessionId, percent); int ii = 0;
tempBuff = new byte[packSize];
// 循环分块读取,直到所有数据读取结束
while (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded())
{
// 分块读取
readSize = request.ReadEntityBody(tempBuff, packSize);
// 复制已读数据块
Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, readSize);
// 记录已上传大小
bytesRead += readSize;
ii++;
if (ii % 30 == 0)//每300kb更新一次进度
{
//计算当前上传文件的百分比
percent = (long)bytesRead * 100 / length;
SetPercent(SessionId, percent);
}
if (readSize == 0)
{
break;
}
} if (!request.IsEntireEntityBodyIsPreloaded())
{
//如果当前状态依然是没有读取完全,通过反射更新预读内容
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = request.GetType();
while (type != null
&& type.FullName != "System.Web.Hosting.ISAPIWorkerRequest"
&& type.FullName != "System.Web.Hosting.IIS7WorkerRequest")
{
type = type.BaseType;
} if (type != null)
{
if (type.FullName == "System.Web.Hosting.ISAPIWorkerRequest")
{
type.GetField("_contentAvailLength", bindingFlags).SetValue(request, buffer.Length);
type.GetField("_contentTotalLength", bindingFlags).SetValue(request, buffer.Length);
type.GetField("_preloadedContent", bindingFlags).SetValue(request, buffer);
type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
}
else
{
type.GetField("_contentTotalLength", bindingFlags).SetValue(request, buffer.Length);
type.GetField("_preloadedContent", bindingFlags).SetValue(request, buffer);
type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
type.GetField("_preloadedLengthRead", bindingFlags).SetValue(request, true);
type.GetField("_preloadedLength", bindingFlags).SetValue(request, buffer.Length);
}
}
}
}
HttpPostedFile imgFile = _request.Files[0];
string fileName = imgFile.FileName;
UpLoadFile(result, imgFile, fileName, upfileConfig, SessionId);
return result;
}
catch (Exception ex)
{
SetPercent(SessionId, 100);
result.IsOk = false;
result.ErrMsg = ex.Message;
return result;
}
Ps: 在不用兼容低版本浏览器的情况下,上传进度已经可以由客户端的JS来完成了。
服务器文件的断点下载
/// <summary>
/// 支持断点下载
/// </summary>
/// <param name="Request"></param>
/// <param name="Response"></param>
/// <param name="filePath">文件的物理地址</param>
private void Down(HttpRequest Request, HttpResponse Response, string filePath)
{
/*断点下载与普通模式不一样的是:
断点下载的请求头信息里面增加一个属性 RANGE: bytes=100000-
响应头里 增加一个属性 Content-Range=bytes 100000-19999/20000
返回状态码为206(Partial Content) 表示头500个字节:Range: bytes=0-499
表示第二个500字节:Range: bytes=500-999
表示最后500个字节:Range: bytes=-500
表示500字节以后的范围:Range: bytes=500-
第一个和最后一个字节:Range: bytes=0-0,-1
同时指定几个范围:Range: bytes=500-600,601-999
*/ // 打开文件
using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
// 获取文件的大小
long fileSize = fileStream.Length;
string range = Request.Headers["Range"]; Response.Clear();
Response.AddHeader("Accept-Ranges", "bytes");
Response.AddHeader("Connection", "Keep-Alive");
Response.Buffer = false; //数据包大小
int pack = 10240; //10Kb
int sleep = 0;
if(this.Speed.HasValue)
{
sleep = (int)Math.Floor(1000.0 * 10 / this.Speed.Value);
} long begin = 0;
long end = fileSize - 1; if (!string.IsNullOrEmpty(range))
{
//获取请求的范围,如果有多个范围,暂时只处理第一个,Range: bytes=500-600,601-999
range = range.Replace("bytes=", "");
range = range.Split(',')[0];
string[] region = range.Split('-');
string startPoint = region[0].Trim();
string endPoint = region[1].Trim();
if (startPoint == "")
{
long.TryParse(endPoint, out end);
begin = fileSize - end;
end = fileSize - 1;
}
else if (endPoint == "")
{
long.TryParse(startPoint, out begin);
end = fileSize - 1;
}
else
{
long.TryParse(startPoint, out begin);
long.TryParse(endPoint, out end);
} Response.StatusCode = 206;
Response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", begin, end, fileSize));
}
//以字节流返回数据
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition"
, "attachment; filename=\"" + HttpUtility.UrlEncode(Request.ContentEncoding.GetBytes(this.FileName)) + "\""); long size = end - begin + 1;
Response.AddHeader("Content-Length", size.ToString()); // 创建一比特数组
byte[] buffer = new Byte[pack];
fileStream.Position = begin; //设置当前流位置
// 当文件大小大于0是进入循环
while (size > 0)
{
// 判断客户端是否仍连接在服务器
if (Response.IsClientConnected)
{
int length = fileStream.Read(buffer, 0, pack);
Response.OutputStream.Write(buffer, 0, length);
// 将缓冲区的输出发送到客户端
Response.Flush(); size = size - length;
if (sleep > 0)
{
Thread.Sleep(sleep);
}
}
else
{
//当用户断开后退出循环
size = -1;
}
}
}
}
iis7上传大文件报404错误的解决
下午测试一个60M的视频文件,报404错误,处理页面里的代码压根没有触发。
请求头里Content-Length属性初始没有出现,就看着360浏览器左下角的百分比一直在涨,到99%后,这个属性才出现,同时抛出404报错信息。
原因是文件超出了 IIS的上传文件大小限制
修改步骤:
1、打开IIS管理器,找到相应的网站。
2、在IIS中双击“请求筛选”打开。
3、点击右边的“编辑功能设置”,打开“编辑请求筛选设置”对话框。
其中的允许的最大容量长度,默认是”30000000“,不到30M。
long length = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
可以正常取到正文大小,从而提前拦截掉太大的文件上传。
但如果文件太大,超出IIS的限制的话,就会出现上面提到的问题,文件会一直上传结束,然后出现404报错。
另外HttpPostedFile的ContentLength属性是int类型,也就是不可能超出整型的上限2147 483 647,大约2G
Web.Config中配置文件大小限制
<system.web>
<httpRuntime maxRequestLength="2097151" executionTimeout="5600" useFullyQualifiedRedirectUrl="true" />
</system.web> <system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="100000000"/>
</requestFiltering>
</security>
</system.webServer>
大文件的上传
如果不需要读取上传进度的话,直接使用request.Files[0]读取上传文件,IIS是会自动对大文件进行磁盘缓存的。而上面的方法为了读取上传进度,把文件先缓冲到内存里再保存,自然无法支持大文件的上传。而且大文件上传也是需要支持断点续传的,否则用户体验太差。
断点续传一方面需要用户上传的每一个文件在服务器上都有唯一的文件名和它对应,从而方便匹配读取之前的上传进度。
另一方面客户端上传文件前先向服务器请求之前的上传进度,然后跳过已上传的部分再按规则分块将文件一块块传到服务器。也就是需要在用户端直接操作文件读取。
.net网站的文件上传读取进度条和断点下载的更多相关文章
- atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7
atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7 1. 实现原理 1 2. 大的文件上传原理::使用applet 1 3. 新的bp 2 1. 性能提升---分割小文件上传 ...
- atitit. 文件上传带进度条 atiUP 设计 java c# php
atitit. 文件上传带进度条 atiUP 设计 java c# php 1. 设计要求 1 2. 原理and 架构 1 3. ui 2 4. spring mvc 2 5. springMVC.x ...
- .Net neatupload上传控件实现文件上传的进度条
1. 引入bin文件 (可以到neatupload官网下载,也可以到教育厅申报系统中找) 2. 将控件加入到工具栏,在工具栏中点鼠标右键,如图: 3. 加入neatuplaod这个文件夹(可以到nea ...
- Asp.net mvc 大文件上传 断点续传 进度条
概述 项目中需要一个上传200M-500M的文件大小的功能,需要断点续传.上传性能稳定.突破asp.net上传限制.一开始看到51CTO上的这篇文章,此方法确实很不错,能够稳定的上传大文件,http: ...
- springMVC+ajax 文件上传 带进度条
前端代码: <form id= "uploadForm"> <p >指定文件名: <input type="text" name= ...
- html5拖拽事件 xhr2 实现文件上传 含进度条
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- Flex4/Flash多文件上传(带进度条)实例分享
要求 必备知识 本文要求基本了解 Adobe Flex编程知识和JAVA基础知识. 开发环境 MyEclipse10/Flash Builder4.6/Flash Player11及以上 演示地址 演 ...
- BootStrap Progressbar 实现大文件上传的进度条
1.首先实现大文件上传,如果是几兆或者几十兆的文件就用基本的上传方式就可以了,但是如果是大文件上传的话最好是用分片上传的方式.我这里主要是使用在客户端进行分片读取到服务器段,然后保存,到了服务器段读取 ...
- HTML5文件上传还有进度条
以下是自学it网--中级班上课笔记 网址:www.zixue.it 需要在chrome,ff,IE10下运行 html页面 <!DOCTYPE html> <html lang=&q ...
随机推荐
- POJ1849Two[DP|树的直径](扩展HDU4003待办)
Two Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 1390 Accepted: 701 Description Th ...
- Quantum Bogo sort浅谈
1.普通的猴子排序(bogo sort) 猴子排序百科 en.wikipedia.org/wiki/Bogosort 不停的随机打乱序列,然后检查,直到排好序 复杂度O(n*n!) while not ...
- 《MySchool数据库设计优化》内部测试
1) 在SQL Server 中,为数据库表建立索引能够( C ). A. 防止非法的删除操作 B. 防止非法的插入操作 C. 提高查询性能 D. 节约数据库的磁盘空间 解析:索引的作用是通过使用索引 ...
- [No000033]码农网-如何锻炼出最牛程序员的编码套路
最近,我大量阅读了Steve Yegge的文章.其中有一篇叫"Practicing Programming"(练习编程),写成于2005年,读后令我惊讶不已: 与你所相信的恰恰相反 ...
- offsetLeft和style.left的区别
offsetLeft 获取的是相对于父对象的左边距 left 获取或设置相对于 具有定位属性(position定义为relative)的父对象 的左边距 如果父div的position定义为relat ...
- Centos5.8 安装 Redmine
安装Ruby 到 /opt/ruby-2.0.0 -p481.tar.gz cd ruby--p481 ./configure --prefix=/opt/ruby- sudo make sudo m ...
- AI图片剪切
来源:http://tieba.baidu.com/p/1203332701?pid=14163166977&cid=78618096662&from=prin#78618096662 ...
- [NOIP2010初赛]烽火传递+单调队列详细整理
P1313 [NOIP2010初赛]烽火传递 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上 ...
- JMS + jboss EAP 6.2 示例
.Net中如果需要消息队列功能,可以很方便的使用微软自带的MSMQ,对应到Java中,这个功能就是JMS(Java Message Service). 下面以Jboss EAP 6.2环境,介绍一下基 ...
- c# 调用win32模拟点击的两种方法
第一种 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...