none
关于获取上传文件大小的问题 RRS feed

  • 问题

  • 现在在用WebForm做一个上传文件的功能,点击上传按钮弹出一个div,div上有三个FileUpload控件(同时最多只能传三个).
    现在碰到了一个问题,就是要限制上传文件的大小在3M以内:
    (1) 如果用js做检测则很方便,不过要用到ActiveX,可惜公司的很多用户计算机使用水平很一般(目前这套系统只针对IE各个版本做了兼容,所以要打开IE对ActiveX的支持,可能很多用户不知道如何操作,而且打开支持后有一定的安全风险,所以我们考虑绕过这个方法);
    (2) 用服务器端判定上传文件大小,如果不符合大小的限定,服务器回发后FileUpload控件中的值会被自动清空,需要用户重新选择要上传的文件,这个问题该如何解决?再一个,服务器端判定文件大小是不是需要先把文件上传到服务器端后才能获取文件大小?对服务器性能的影响如何?
    (3) FileUpload控件默认上传文件的大小限制是4M,如果超出4M则无反应,请问在超出4M的情况下会不会引发异常?这个异常应该如何捕捉?
    2009年12月27日 3:24

答案

  • 你好,如果想在客户端判断文件大小,又不想安装插件,可以考虑使用flash来做一个上传控件。
    • 已标记为答案 KeFang Chen 2009年12月31日 3:55
    2009年12月28日 8:59
    版主
  • 你好,

    这个如果不用ACTIVEX,只能在服务器端获得。但是当上传文件太大的时候就会报错,无法获得。有一种方法可以避免发生这样的错误。你可以参考下面的代码。当整个body的大小超过1024,就会进入那里面的方法。

     public class test : IHttpModule
        {
            #region IHttpModule Members
    
            public void Dispose()
            {
               
            }
    
            public void Init(HttpApplication context)
            {
                context.BeginRequest += new EventHandler(application_BeginRequest);
            }
    
    
            void application_BeginRequest(object sender, EventArgs e)
            {
                HttpApplication ha = sender as HttpApplication;
                HttpContext context = ha.Context;
                if (ha.Context.Request.ContentLength > 1024)
                {
                    IServiceProvider provider = (IServiceProvider)context;
                    HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
                    FileStream fs = null;
                    // Check if body contains data
                    if (wr.HasEntityBody())
                    {
                        // get the total body length
                        int requestLength = wr.GetTotalEntityBodyLength();
                        // Get the initial bytes loaded
                        int initialBytes = 0; //wr.GetPreloadedEntityBody().Length;
    
                        if (!wr.IsEntireEntityBodyIsPreloaded())
                        {
                            byte[] buffer = new byte[100];
                            //string[] fileName = context.Request.QueryString["fileName"].Split(new char[] { '\\' });
                            // fs = new FileStream(context.Server.MapPath("~/Files/temp.pdf"), FileMode.CreateNew);
                            // Set the received bytes to initial bytes before start reading
                            int receivedBytes = initialBytes;
                            while (requestLength - receivedBytes >= initialBytes)
                            {
                                // Read another set of bytes
                                initialBytes = wr.ReadEntityBody(buffer, buffer.Length);
                                // Write the chunks to the physical file
                                // fs.Write(buffer, 0, buffer.Length);
    
                                // Update the received bytes
                                receivedBytes += initialBytes;
                            }
                            initialBytes = wr.ReadEntityBody(buffer, requestLength - receivedBytes);
    
                        }
                    }
                    fs.Flush();
                    fs.Close();
                    ha.Context.Response.Redirect("~/Home/Create/");
                }
    
            }   
            #endregion
        }

    Microsoft Online Community Support
    • 已标记为答案 KeFang Chen 2009年12月31日 3:55
    2009年12月28日 4:46

全部回复

  • FileUpload服务端判断上传文件大小可以在上传前判断
     if (FileUpload1.PostedFile.ContentLength>= 3072000)
                {
                    ScriptManager.RegisterStartupScript(this, GetType(), "jsalert", "alert('文件大小不允许超过3M')", true);
                }
    else
    {
           //上传
    }
    FileUpload控件默认上传文件的大小限制是4M,如果超过4m可以在web.config里添加配置节点
    <httpRuntime useFullyQualifiedRedirectUrl="true" maxRequestLength="1550000" executionTimeout="500"/>

    服务端判断上传大小后不符合限定,自动清空,这个是合理的把既然你限定制定大小,超过这个限定,用户想上传肯定要从新选择文件才可上传了。否则你可以用ViewState保存上传文件


    希望如下文章对你有帮助

    http://www.infoq.com/cn/news/2008/01/handling-large-uploads


    大附件上传
    http://www.cnblogs.com/downmoon/archive/2008/01/29/1057726.html
    http://www.cnblogs.com/downmoon/archive/2009/02/05/1384931.html


    啥叫乐观-得瑟的最高境界
    2009年12月27日 4:35
  • 感谢二位的回复  :D
    第一点:"FileUpload服务端判断上传文件大小可以在上传前判断",这一点经过验证,个人感觉应该是先上传到服务器然后才能获取文件的大小,我上传过一个1G以上的大文件,需要等一段时间才能够获取文件的大小;
    第二点:如果上传过大的文件后,IE会显示"无法显示该页面",我的意思是说,碰到上述的情况会不会有什么异常被引发?如何捕捉这种情况并给予提示?
    2009年12月28日 3:31
  • 你好,

    这个如果不用ACTIVEX,只能在服务器端获得。但是当上传文件太大的时候就会报错,无法获得。有一种方法可以避免发生这样的错误。你可以参考下面的代码。当整个body的大小超过1024,就会进入那里面的方法。

     public class test : IHttpModule
        {
            #region IHttpModule Members
    
            public void Dispose()
            {
               
            }
    
            public void Init(HttpApplication context)
            {
                context.BeginRequest += new EventHandler(application_BeginRequest);
            }
    
    
            void application_BeginRequest(object sender, EventArgs e)
            {
                HttpApplication ha = sender as HttpApplication;
                HttpContext context = ha.Context;
                if (ha.Context.Request.ContentLength > 1024)
                {
                    IServiceProvider provider = (IServiceProvider)context;
                    HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
                    FileStream fs = null;
                    // Check if body contains data
                    if (wr.HasEntityBody())
                    {
                        // get the total body length
                        int requestLength = wr.GetTotalEntityBodyLength();
                        // Get the initial bytes loaded
                        int initialBytes = 0; //wr.GetPreloadedEntityBody().Length;
    
                        if (!wr.IsEntireEntityBodyIsPreloaded())
                        {
                            byte[] buffer = new byte[100];
                            //string[] fileName = context.Request.QueryString["fileName"].Split(new char[] { '\\' });
                            // fs = new FileStream(context.Server.MapPath("~/Files/temp.pdf"), FileMode.CreateNew);
                            // Set the received bytes to initial bytes before start reading
                            int receivedBytes = initialBytes;
                            while (requestLength - receivedBytes >= initialBytes)
                            {
                                // Read another set of bytes
                                initialBytes = wr.ReadEntityBody(buffer, buffer.Length);
                                // Write the chunks to the physical file
                                // fs.Write(buffer, 0, buffer.Length);
    
                                // Update the received bytes
                                receivedBytes += initialBytes;
                            }
                            initialBytes = wr.ReadEntityBody(buffer, requestLength - receivedBytes);
    
                        }
                    }
                    fs.Flush();
                    fs.Close();
                    ha.Context.Response.Redirect("~/Home/Create/");
                }
    
            }   
            #endregion
        }

    Microsoft Online Community Support
    • 已标记为答案 KeFang Chen 2009年12月31日 3:55
    2009年12月28日 4:46
  • 感谢二位的回复  :D
    第一点:"FileUpload服务端判断上传文件大小可以在上传前判断",这一点经过验证,个人感觉应该是先上传到服务器然后才能获取文件的大小,我上传过一个1G以上的大文件,需要等一段时间才能够获取文件的大小;
    第二点:如果上传过大的文件后,IE会显示"无法显示该页面",我的意思是说,碰到上述的情况会不会有什么异常被引发?如何捕捉这种情况并给予提示?

    你可以考虑ftp模式上传   研究一下qq中转站
    2009年12月28日 8:32
  • 第二点:如果上传过大的文件后,IE会显示"无法显示该页面",我的意思是说,碰到上述的情况会不会有什么异常被引发?如何捕捉这种情况并给予提示?

    我记得msdn有人问问过这样的问题,问如何捕获这个异常,好像是捕获不到,只能把web.config 节点httpRuntime属性maxRequestLength和executionTimeout设置大一些来避免,因为我最近与遇到这个问题,上传大文件肯定不能走80端口上传.可以尝试ftp模式
    或httpModules.如果你有更好的解决方案你麻烦你通知我以下.谢谢

    参考:http://hi.baidu.com/xuguoyi/blog/item/4aee86ca0380c883c817685b.html
    啥叫乐观-得瑟的最高境界
    2009年12月28日 8:56
  • 你好,如果想在客户端判断文件大小,又不想安装插件,可以考虑使用flash来做一个上传控件。
    • 已标记为答案 KeFang Chen 2009年12月31日 3:55
    2009年12月28日 8:59
    版主
  • 如果文件不是很大的话,可以直接用JS方法判断文件大小的
    方法如下:

    function checkFileSize(file)
    {
     try
     {
      var image=new Image();
      image.dynsrc=file;
      if(image.fileSize>1024*1024*10)
       return alert('上传失败,错误原因:请控制上传的文件大小在10M以内!');
     }catch(e){}
    }
    这样就可以了,如果文件太大的话,也可以验证,但是就是会卡下页面,原因是把文件当成图片预存进Image对象中,文件大,耗时长,故不适合上传太大的文件
    经过我的测试,最大放100M以内的文件最合适,116M的文件预存需要2~4秒!100M以内的就眨眼OK了!!!
    希望能帮到你
    2010年1月4日 7:41
  • 不是也得安装flash插件么
    2011年9月14日 1:02