现在的位置: 首页 > 综合 > 正文

asp.net 分块上传文件

2017年11月06日 ⁄ 综合 ⁄ 共 5834字 ⁄ 字号 评论关闭

      在ASP.Net中,大文件上传一直是个棘手的问题。在WEB.Config文件中有对上传文件大小的限制。对于稍大点的文件可以适当更改配置,但我们不能无限制的括大它,这是由ASP.Net的上传机制所决定的,因为.Net是把文件全部加载到内存中才可以进行操作的(MSDN上说,对于过大的文件实际上也还是要放在硬盘上缓冲的)。对于此问题,最简单的解决办法是使用别人开发的组件,如:

例如,若想将上传文件的上限提高至20MB,我们只需要这样修改:

view plaincopy to clipboardprint?
<system.web>  
  <httpRuntime executionTimeout="240" maxRequestLength="20480" />  
</system.web> 
<system.web>
  <httpRuntime executionTimeout="240" maxRequestLength="20480" />
</system.web>

FileUploader.NET (MediaChase公司,$310以上)
RadUpload (Telerik公司,$249)
NeatUpload (免费,遵守LGPL协议)
但有时候,我们并不想使用组件,那还有一个解决办法,在服务器端截获上传事件,并把数据分块上传。代码如下:

 1、Config如下配置

<httpModules>     
      <add name="upFile" type="HttpUploadModule"/>
    </httpModules>

    <httpRuntime executionTimeout="240" maxRequestLength="10240" requestValidationMode="2.0" />

2、如下实现接口IHttpModule 

using System;  
using System.Collections;  
using System.Collections.Specialized;  
using System.Globalization;  
using System.IO;  
using System.Text;  
using System.Web;  
using System.Reflection;  
//实现IHttpModule接口  
public class HttpUploadModule : IHttpModule 

    ///<summary> 
    ///默认无参构造函数 
    ///</summary> 
    public HttpUploadModule() 
    { 
    } 
    ///<summary> 
    ///初始化,在此添加事件的响应 
    ///</summary> 
    ///<param name="application">Web应用程序对像</param> 
    public void Init(HttpApplication application) 
    { 
        //订阅响应HTTP请求事件  
        application.BeginRequest += new EventHandler(this.Application_BeginRequest); 

    } 
    ///<summary> 
    ///释放使用的资源 
    ///</summary> 
    public void Dispose() 
    { 
        // 
        //TODO:如果需要手工为类做一些清除工作,在此添加代码 
        // 
    } 
    ///<summary> 
    ///开始一个HTTP请求事件的处理 
    ///</summary> 
    ///<param name="sender"></param> 
    ///<param name="e"></param> 
    private void Application_BeginRequest(Object sender, EventArgs e) 
    { 
        HttpApplication app = sender as HttpApplication;            //获得Web应用程序对像 

        HttpWorkerRequest request = GetWorkerRequest(app.Context);  //获得Http请求对像 

        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); 
                } 
            } 
        } 
    } 
 
    ///<summary> 
    ///获得Http请求对像 
    ///</summary> 
    ///<param name="context">Http请求内容</param> 
    ///<returns>Http请求对像</returns> 
    HttpWorkerRequest GetWorkerRequest(HttpContext context) 
    { 
        IServiceProvider provider = (IServiceProvider)HttpContext.Current; 
        return (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest)); 

    } 
 
    ///<summary>  
    ///传入已上传完的数据  
    ///</summary>  
    ///<param name="request">Http请求对像</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); 

        } 
    } 
    /// <summary> 
    /// 比较两个字符串指定位置的指定长度是否相等 
    /// 忽略大小写及区域不同 
    /// </summary> 
    /// <param name="s1">要比较的第一个字符串</param> 
    /// <param name="s2">要比较的第二个字符串</param> 
    /// <returns> 
    /// 小于零 str1 中的子字符串小于 str2 中的子字符串。 
    /// 等于零子字符串相等,或者 length 为零。 
    /// 大于零 str1 中的子字符串大于 str2 中的子字符串。 
    /// </returns> 
    private static bool StringStartsWithAnotherIgnoreCase(string str1, string str2) 

    { 
        return (string.Compare(str1, 0, str2, 0, str2.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"); 

    } 
}

抱歉!评论已关闭.