文件上传到服务器时的进度读取

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网站的文件上传读取进度条和断点下载的更多相关文章

  1. atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7

    atitit.文件上传带进度条的实现原理and组件选型and最佳实践总结O7 1. 实现原理 1 2. 大的文件上传原理::使用applet 1 3. 新的bp 2 1. 性能提升---分割小文件上传 ...

  2. 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 ...

  3. .Net neatupload上传控件实现文件上传的进度条

    1. 引入bin文件 (可以到neatupload官网下载,也可以到教育厅申报系统中找) 2. 将控件加入到工具栏,在工具栏中点鼠标右键,如图: 3. 加入neatuplaod这个文件夹(可以到nea ...

  4. Asp.net mvc 大文件上传 断点续传 进度条

    概述 项目中需要一个上传200M-500M的文件大小的功能,需要断点续传.上传性能稳定.突破asp.net上传限制.一开始看到51CTO上的这篇文章,此方法确实很不错,能够稳定的上传大文件,http: ...

  5. springMVC+ajax 文件上传 带进度条

    前端代码: <form id= "uploadForm"> <p >指定文件名: <input type="text" name= ...

  6. html5拖拽事件 xhr2 实现文件上传 含进度条

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. Flex4/Flash多文件上传(带进度条)实例分享

    要求 必备知识 本文要求基本了解 Adobe Flex编程知识和JAVA基础知识. 开发环境 MyEclipse10/Flash Builder4.6/Flash Player11及以上 演示地址 演 ...

  8. BootStrap Progressbar 实现大文件上传的进度条

    1.首先实现大文件上传,如果是几兆或者几十兆的文件就用基本的上传方式就可以了,但是如果是大文件上传的话最好是用分片上传的方式.我这里主要是使用在客户端进行分片读取到服务器段,然后保存,到了服务器段读取 ...

  9. HTML5文件上传还有进度条

    以下是自学it网--中级班上课笔记 网址:www.zixue.it 需要在chrome,ff,IE10下运行 html页面 <!DOCTYPE html> <html lang=&q ...

随机推荐

  1. HDU2639Bone Collector II[01背包第k优值]

    Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  2. wamp5设置外网访问方法

    1.安装完Wamp5之后,从外网访问网页时存在无法访问问题. 2.phpmyadmin外网没法访问 1.解决办法: 打开wamp的托盘图标(右下角),找到"Config files" ...

  3. javascript高级程序设计 读书笔记1

    第二章  在HTML中使用JS 加载JS有三种:行内,head头部和外部链接JS   最好使用外部链接<script src="example.js" ></sc ...

  4. java 28 - 6 JDK7的新特性

    JDK7的新特性: 二进制字面量 数字字面量可以出现下划线 switch 语句可以用字符串 泛型简化 异常的多个catch合并 try-with-resources 语句 二进制字面量 JDK7开始, ...

  5. linux下内网端口转发工具:linux版lcx [实现远程内网维护]

    这个工具以前使用的初衷是内网渗透,需要将内网ssh端口转发到外网服务器上.但这个工具同样适用于运维工程师进行远程内网维护. 当然这一切的前提是内网可以访问外网,检测方法当然就是直接ping 一个外网I ...

  6. poj[1185]炮兵阵地

    Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo ...

  7. Android测试之Monkey

    自己用的测试 C:\Users\Star>adb shell monkey -p com.cmstop.android --monitor-native-crashes -- pct-touch ...

  8. js物理弹性窗口

    js物理弹性窗口 点击下载代码

  9. Delphi项目的构成

    Hello.cfg 項目配置文件 Hello.dof 項目選項文件 Hello.dpr 項目文件 Hello.exe 應用程序 Hello.res 資源文件 HelloWorld.dcu 窗口編譯文件 ...

  10. 047医疗项目-模块四:采购单模块—采购单审核提交(Dao,Service,Action三层)

    我们之前把采购单都审核了,这篇文章说的就是审核之后提交. 其实就是改变(update)采购单的审核状态. 需求: 用户要先查看采购单的内容. 查看采购单页面:页面布局同采购单修改页面. 选择审核结果. ...