轉自 http://blog.163.com/soldier_200/blog/static/1552123320091115319532/
sp.net分塊上傳大文件
1.一般的在Asp.net裏上傳文件都是10m左右,要做到大文件上傳,必須要改web.config,不過改了web.config有時候也上傳不成功,那是每次上傳的文件太大,瀏覽器在這個過程中會超時,採用分塊上傳的方法就可以避免這種情況。
2.分塊上傳就是利用post的方法,把數據分塊上傳,每塊上傳的數據量少,不會引起超時的問題。不說了,看代碼吧。
Code
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
namespace Web
{
//實現IHttpModule接口
public class HttpUploadModule : IHttpModule
{
public HttpUploadModule() { }
public void Dispose()
{
}
public void Init(HttpApplication application)
{
//訂閱事件
application.BeginRequest += new EventHandler(this.Application_BeginRequest);
}
private void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
HttpWorkerRequest request = GetWorkerRequest(app.Context);
Encoding encoding = app.Context.Request.ContentEncoding;
int bytesRead = 0; // 已讀數據大小
int read; // 當前讀取的塊的大小
int count = 8192; // 分塊大小
byte[] buffer; // 保存所有上傳的數據
if (request != null)
{
// 返回 HTTP 請求正文已被讀取的部分。
byte[] tempBuff = request.GetPreloadedEntityBody(); //要上傳的文件
// 如果是附件上傳
if (tempBuff != null && IsUploadRequest(app.Request)) //判斷是不是附件上傳
{
// 獲取上傳大小
long length = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
buffer = new byte[length];
count = tempBuff.Length; // 分塊大小
// 將已上傳數據複製過去
//
Buffer.BlockCopy(tempBuff, //源數據
0, //從0開始讀
buffer, //目標容器
bytesRead, //指定存儲的開始位置
count); //要複製的字節數。
// 開始記錄已上傳大小
bytesRead = tempBuff.Length;
// 循環分塊讀取,直到所有數據讀取結束
while (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded() && bytesRead < length)
{
// 如果最後一塊大小小於分塊大小,則重新分塊
if (bytesRead + count > length)
{
count = (int)(length - bytesRead);
tempBuff = new byte[count];
}
// 分塊讀取
read = request.ReadEntityBody(tempBuff, count);
// 複製已讀數據塊
Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, read);
// 記錄已上傳大小
bytesRead += read;
}
if (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded())
{
// 傳入已上傳完的數據
InjectTextParts(request, buffer);
}
}
}
}
HttpWorkerRequest GetWorkerRequest(HttpContext context)
{
IServiceProvider provider = (IServiceProvider)HttpContext.Current;
return (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
}
/// <summary>
/// 傳入已上傳完的數據
/// </summary>
/// <param name="request"></param>
/// <param name="textParts"></param>
void InjectTextParts(HttpWorkerRequest request, byte[] textParts)
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = request.GetType();
while ((type != null) && (type.FullName != "System.Web.Hosting.ISAPIWorkerRequest"))
{
type = type.BaseType;
}
if (type != null)
{
type.GetField("_contentAvailLength", bindingFlags).SetValue(request, textParts.Length);
type.GetField("_contentTotalLength", bindingFlags).SetValue(request, textParts.Length);
type.GetField("_preloadedContent", bindingFlags).SetValue(request, textParts);
type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
}
}
private static bool StringStartsWithAnotherIgnoreCase(string s1, string s2)
{
return (string.Compare(s1, 0, s2, 0, s2.Length, true, CultureInfo.InvariantCulture) == 0);
}
/// <summary>
/// 是否爲附件上傳
/// 判斷的根據是ContentType中有無multipart/form-data
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
bool IsUploadRequest(HttpRequest request)
{
return StringStartsWithAnotherIgnoreCase(request.ContentType, "multipart/form-data");
}
}
}
3.用法
(1)修改web.config
<system.web>
<httpModules>
<add type="HttpModelApp.HttpUploadModule, HttpModelApp" />
</httpModules>
<httpRuntime maxRequestLength="2000000" executionTimeout="300" />
</system.web>
(2)aspx
<form runat="server" enctype="multipart/form-data" method="post">
<div>
<input type="file" runat="server"><br />
<asp:Button runat="server" Text="上傳" /><br />
<asp:Label runat="server"></asp:Label>
</div>
</form>
(3)aspx.cs
protected void Button1_Click(object sender, EventArgs e)
{
//要保存的位置
string strDesPath = "D:\\";
string strFileName = this.firstFile.PostedFile.FileName;
strFileName = strDesPath + strFileName.Substring(strFileName.LastIndexOf("\\"));
//
this.firstFile.PostedFile.SaveAs(strFileName);
this.Label1.Text = "文件保存到了:" + strFileName;
}
4.大文件上傳的限制
雖然可以上傳大文件,但是這個大小也是有限制的,不能超過2G的大小。