ASP.NET MVC之文件上传【二】(九)

前言

上一节咱们讲了简单的上传以及须要注意的地方,查相关资料时,感受上传里面涉及到的内容仍是比较多,因而就将上传这一块分为几节来处理,同时后续也会讲到关于作上传时遗漏的C#应该注意的地方,及时进行查漏补缺,尽可能将这一块完善起来。web

引入

上一节咱们讲到了上传这一块,在评论中有园友提出未涉及到大文件的上传这一块,思前想后仍是来试着作作,毕竟以前没怎么去仔细考虑过这个问题,尤为还能够联系实际开发中建立文件夹等一系列问题,同时关于上传在网上随便找找都充斥着大量的组件,咱们何须再去造轮子,我须要作的是只是对基础的回顾以及进一步深刻以及在作的过程当中发现一些细节性的问题并解决就足矣,不喜勿喷。测试

深刻上传

再次声明对于上传能够显示上传进度之类咱们不去作过多探讨,有这样的组件,自行去找,咱们只需实现比较核心的这一块便可。ui

咱们能够想象这同样一个场景:好比在博客园中,每一个博客者均可以上传文件如图片、脚本之类,咱们能够经过园友名称来建立每一个园友上传的文件,接下来咱们来实现这样的一个场景。spa

既然是对应博客的名称建立文件,也就是须要对应的博客这样的一个类。以下:
3d

    public class BlogSample
    {
        public string UserName { get; set; }

        public string Id { get; set; }
    }

咱们经过博客名称来建立文件夹并在该文件夹下以惟一的Id来建立子文件夹,在该Id文件夹下的附件( atttachment )中存储上传的文件。接下来咱们须要梳理整个上传文件的过程。难道就把要上传的文件直接到上传到对应的文件夹吗,这么作显然不是最优的,当有上传中断时则在文件夹建立的文件不是完整的则是垃圾文件,而咱们直接先建立一个临时文件,即便上传失败咱们能够按期清理临时文件也就是垃圾文件,若未中断,上传完毕时则将临时文件移动到咱们对应的文件夹中。经过咱们实际下载文件时很明显看的出也是这么作的。接下来咱们开始进行实现。code

(1)咱们给出一个关于上传的 UploadManager 静态类,咱们能够写死上传的文件夹名称或者经过配置文件自定义上传文件夹名称。orm

        static UploadManager()
        {
            //从配置文件中获取上传文件夹
            if (String.IsNullOrWhiteSpace(WebConfigurationManager.AppSettings["UploadFolder"]))
                UploadFolderRelativePath = @"~/upload";
            else
                UploadFolderRelativePath = WebConfigurationManager.AppSettings["UploadFolder"];

            UploadFolderPhysicalPath = HostingEnvironment.MapPath(UploadFolderRelativePath);

            if (!Directory.Exists(UploadFolderPhysicalPath))
                Directory.CreateDirectory(UploadFolderPhysicalPath);
        }

上述已经代表能够自定义上传文件夹在配置文件中(给出上传虚拟路径),例如以下:blog

  <!--<add key="UploadFolder" value="~/UploadFile/">-->

(2)保存文件的核心方法图片

        [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
        public static bool SaveFile(Stream stream, string fileName, string userName, string guid)
        {
            string tempPath = string.Empty, targetPath = string.Empty;

            try
            {
                string tempFileName = GetTempFilePath(fileName);

                if (userName != null)
                {
                    var contentType = userName;
                    var contentId = guid;

                    tempPath = GetTempFilePath(tempFileName);
                    targetPath = GetTargetFilePath(fileName, contentType, contentId, string.Empty, FilesSubdir);


                    //若上传文件夹中子文件夹未存在则建立
                    var file = new FileInfo(targetPath);
                    if (file.Directory != null && !file.Directory.Exists)
                        file.Directory.Create();

                    using (FileStream fs = File.Open(tempPath, FileMode.Append))
                    {
                        if (stream.Length > 0)
                        {
                            SaveFile(stream, fs);
                        }
                        fs.Close();
                    }
                    //上传完毕将临时文件移动到目标文件
                    File.Move(tempPath, targetPath);
                }
            }
            catch (Exception)
            {
                // 若上传出错,则删除上传到文件夹文件
                if (File.Exists(targetPath))
                    File.Delete(targetPath);

                // 删除临时文件
                if (File.Exists(tempPath))
                    File.Delete(tempPath);

                return false;
            }
            finally
            {
                // 删除临时文件
                if (File.Exists(tempPath))
                    File.Delete(tempPath);
            }
            return true;
        }

(3)循环读取流到文件流中ip

         /// <summary>
        /// 循环读取流到文件流中
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="fs"></param>
        public static void SaveFile(Stream stream, FileStream fs)
        {
            var buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
            {
                fs.Write(buffer, 0, bytesRead);
            }
        }

(4)开始写入测试数据,进行调用方法:

            var testSample = new BlogSample() { UserName = "xpy0928", Id = Guid.NewGuid().ToString("N") };
            if (ModelState.IsValid)
            {
                var fileName = bModel.BlogPhoto.FileName;
                var success = UploadManager.SaveFile(bModel.BlogPhoto.InputStream, fileName, testSample.UserName, testSample.Id);
                if (!success)
                {
                    // TODO(your code)
                }
                //var filePath = Server.MapPath(string.Format("~/{0}", "File"));
                //bModel.BlogPhoto.SaveAs(Path.Combine(filePath, fileName));
                ModelState.Clear();
            }

接下来咱们来进行测试,经过上传一个84M的文件来看看效果(稍等片刻,文件有点大)。

很差意思,令我大失所望,和昨天出现的错误不同,今天出错是:超过最大请求长度。咱们接下来再来看看昨天所说,个人IIS为10.0,也就是在IIS 7+上,经过昨天那样设置应该是没问题的,难道和另一个设置有关吗,咱们看看配置文件中的配置。

<httpRuntime targetFramework="4.5"/>

未进行设置,超过其默认设置28.6M就出错了吗,咱们再设置为2G看看。

<httpRuntime targetFramework="4.5" executionTimeout="1100"  maxRequestLength="2147483647"/>

好,上传成功也未出现上述错误。

结语

这一节咱们讲了一下利用流来进行大文件的处理,不过仍是出现了一点小问题,和昨天再一块儿作一次总结:

(1)在IIS 5和IIS 6中,默认文件上传的最大为4兆,当上传的文件大小超过4兆时,则会获得错误信息,可是咱们经过以下来设置文件大小。

<system.web>
  <httpRuntime maxRequestLength="2147483647" executionTimeout="100000" />
</system.web>

(2)在IIS 7+,默认文件上传的最大为28.6兆,当超过其默认设置大小,一样会获得错误信息,可是咱们却能够经过以下来设置文件上传大小(同时也要进行如上设置)

<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="2147483647" />
    </requestFiltering>
  </security>
</system.webServer>

关于在配置文件中如何设置文件大小而不出错,总算作了一个最终的总结,有收获,继续Fighting。

相关文章
相关标签/搜索