IHttpModule 分块上传大文件

本文介绍了一种在ASP.NET中实现大文件分块上传的方法,通过修改web.config配置并利用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的大小。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值