IHttpModule 分塊上傳大文件

來源:http://www.cnblogs.com/HeroBeast/archive/2008/03/18/1084874.html

1.一般的在Asp.net裏上傳文件都是10m左右,要做到大文件上傳,必須要改web.config,不過改了web.config有時候也上傳不成功,那是每次上傳的文件太大,瀏覽器在這個過程中會超時,採用分塊上傳的方法就可以避免這種情況。
2.分塊上傳就是利用post的方法,把數據分塊上傳,每塊上傳的數據量少,不會引起超時的問題。不說了,看代碼吧。

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using System.IO;
using System.Reflection;
using System.Threading;
using System.Text;
using System.Globalization;

/// <summary>
/// 實現IHttpModule接口
/// </summary>
public class HttpUploadModule : IHttpModule
{
    
public HttpUploadModule()
    {

    }

    
public void Init(HttpApplication application)
    {
        
//訂閱事件
        application.BeginRequest += new EventHandler(this.Application_BeginRequest);
    }

    
public void Dispose()
    {
    }

    
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,                      //從開始讀
                    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
<httpModules>
            
<add name="up" type="HttpUploadModule"/>
 
</httpModules>
<httpRuntime maxRequestLength="2000000" executionTimeout="300" />
(2)aspx
 <form id="form1" runat="server" enctype="multipart/form-data">
    
<div>
    
        
<asp:FileUpload ID="FileUpload1" runat="server" />
        
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />    
    
</div>
    
</form>
 (3)aspx.cs
  protected void Button1_Click(object sender, EventArgs e)
    {
        
string strDesPath = "D:/";
        
string strFileName = this.FileUpload1.PostedFile.FileName;
        strFileName 
= strDesPath + strFileName;//.Substring(strFileName.LastIndexOf("/"));
        
//
        this.FileUpload1.PostedFile.SaveAs(strFileName);
        Response.Write(
"文件保存到了:" + strFileName);
    }
4.大文件上傳的限制
  雖然可以上傳大文件,但是這個大小也是有限制的,不能超過2G的大小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章