• 分享一篇关于C#大文件上传的整个过程


    简单写个小例子,记录一下此次大文件上传遇到的所有问题。

    一、客户端(使用winform窗体实现)

    具体功能:

      • 点击“选择”按钮,选择要上传的文件
      • 点击“上传文件”按钮,上传该文件调用UpLoad_Request(string address, string fileNamePath, string saveName, ProgressBar progressBar)方法
      • 在客户端显示上传进度,已经时间,平均速度,上传状态,上传大小
    FileUpload 文件上传类代码:
    public class FileUpload
        {  
            /// <summary>
           /// 上传文件
           /// </summary>
           /// <param name="address">文件上传到服务器的路径</param>
           /// <param name="fileNamePath">要上传的本地路径(全路径)</param>
           /// <param name="saveName">文件上传后的名称</param>
           /// <returns>成功返回1,失败返回0</returns>
            public static int UpLoad_Request(string address, string fileNamePath, string saveName, ProgressBar progressBar)
            {
                int returnValue = 0;
                //要上传的文件
                FileStream fs = new FileStream(fileNamePath, FileMode.Open, FileAccess.Read);
                //二进制对象
                BinaryReader r = new BinaryReader(fs);
                //时间戳
                string strBoundary = "----------" + DateTime.Now.Ticks.ToString("x");
                byte[] boundaryBytes = Encoding.ASCII.GetBytes("
    --" + strBoundary + "
    ");
                //请求的头部信息
                StringBuilder sb = new StringBuilder();
                sb.Append("--");
                sb.Append(strBoundary);
                sb.Append("
    ");
                sb.Append("Content-Disposition: form-data; name="");
                sb.Append("file");
                sb.Append(""; filename="");
                sb.Append(saveName);
                sb.Append("";");
                sb.Append("
    ");
                sb.Append("Content-Type: ");
                sb.Append("application/octet-stream");
                sb.Append("
    ");
                sb.Append("
    ");
                string strPostHeader = sb.ToString();
                byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader);
    
                // 根据uri创建HttpWebRequest对象   
                HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(address));
                //对发送的数据不使用缓存
                httpReq.AllowWriteStreamBuffering = false;
                //设置获得响应的超时时间(3min)
                httpReq.Timeout = 180000;
                httpReq.KeepAlive = true;
                httpReq.ProtocolVersion = HttpVersion.Version11;
    
                httpReq.Method = "POST";
                //对发送的数据不使用缓存   
                //httpReq.AllowWriteStreamBuffering = true;
                //设置获得响应的超时时间(300s)   
                //httpReq.Timeout = 300000;
                httpReq.ContentType = "multipart/form-data; boundary=" + strBoundary;
                long length = fs.Length + postHeaderBytes.Length + boundaryBytes.Length;
                long fileLength = fs.Length;
                httpReq.ContentLength = length;
                try
                {
                    progressBar.Maximum = int.MaxValue;
                    progressBar.Minimum = 0;
                    progressBar.Value = 0;
                    //每次上传8k  
                    int bufferLength = 8192;
                    byte[] buffer = new byte[bufferLength]; //已上传的字节数   
                    long offset = 0;         //开始上传时间   
                    DateTime startTime = DateTime.Now;
                    int size = r.Read(buffer, 0, bufferLength);
                    Stream postStream = httpReq.GetRequestStream();         //发送请求头部消息   
                    postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                    while (size > 0)
                    {
                        postStream.Write(buffer, 0, size);
                        offset += size;
                        progressBar.Value = (int)(offset * (int.MaxValue / length));
                        TimeSpan span = DateTime.Now - startTime;
                        double second = span.TotalSeconds;
                        Application.DoEvents();
                        size = r.Read(buffer, 0, bufferLength);
                    }
                    //添加尾部的时间戳   
                    postStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    postStream.Close();
                    //获取服务器端的响应   
                    WebResponse webRespon = httpReq.GetResponse();
                    Stream s = webRespon.GetResponseStream();
                    //读取服务器端返回的消息  
                    StreamReader sr = new StreamReader(s);
                    String sReturnString = sr.ReadLine();
                    s.Close();
                    sr.Close();
                    if (sReturnString == "Success")
                    {
                        progressBar.Value = 100;
                        returnValue = 1;
                    }
                    else if (sReturnString == "Error")
                    {
                        returnValue = 0;
                        progressBar.Value = 0;//错误就得重新上传,进度条置零
                    }
                }
                catch(Exception ex)
                {
                      Console.WriteLine(ex.Message);
                    returnValue = 0;
                }
                finally
                {
                    fs.Close();
                    r.Close();
                }
                return returnValue;
            }
    
        }

    具体实现代码如下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace UpFileClient
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            string filePath = "";
            string FileName = "";
            private void btnSelect_Click(object sender, EventArgs e)
            {
                //创建文件弹出选择窗口(包括文件名)对象
                OpenFileDialog ofd = new OpenFileDialog();
                //判断选择的路径
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    this.txtSoundPath.Text = ofd.FileName.ToString();
                }
                filePath = this.txtSoundPath.Text;
            }
    
            private void btnUpLoad_Click(object sender, EventArgs e)
            {
                try {
                    //上传服务器的地址(web服务)
                 string address = "http://localhost:61501/WebService/SaveFileWebForm.aspx";
                    //上传后文件保存的名称
                    string saveName = DateTime.Now.ToString("yyyyMMddHHmmss");
                    int count = FileUpload.UpLoad_Request(address, filePath, saveName, this.progressBar1);
                    if (count > 0)
                    {
                        MessageBox.Show("上传文件成功!");
                    }
                    else
                    {
                        MessageBox.Show("上传文件失败!");
                    }  
                }catch(Exception ex)
                {
    
                    Console.WriteLine(ex.Message);
                }          
           }   
        }
    }

    界面显示

       

    二、服务器端-提供文件上传服务

    1、创建一个web mvc项目,在创建一个webservice文件夹,在文件夹下创建一个SaveFileWebForm.axpx接口,

    设置这个页面为项目起始页,打开这个页面,右键查看代码,编写服务器端代码,运行项目

    项目结构:

     客户端上传文件时,服务器端(SaveFileWebForm.axpx)需要访问的到,(注:先运行服务器程序项目,在运行客户端程序项目)

    文件保存路径和文件保存名可以根据实际需要设置

    服务器端源码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace SaveFileWebService.WebService
    {
        public partial class SaveFileWebForm : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (Request.Files.Count > 0)
                {
                    try
                    {
                        //得到客户端上传的文件
                        HttpPostedFile file = Request.Files[0];
                        //服务器端要保存的路径
                        string filePath = "D:\Test\" + file.FileName + ".mp3";
                        file.SaveAs(filePath);
                        //返回结果
                        Response.Write("Success");
                    }
                    catch
                    {
                        Response.Write("Error");
                    }
                }
                else
                {
                    Response.Write("Error1");
                } 
            }
        }
    }

    按照上面过程走下来,本来以为已经可以大功告成了,结果问题来了,小文件上传没问题,

    超了4m的文件上传不了,报错引发的异常:“System.Net.WebException”(位于 System.dll 中)报400错误

    在使用FileUpload控件时不少人遇到过上传文件失败的问题,其实是出于安全的原因,.Net运行时对请求文件最大长度作了限制,开发者需要手动修改下配置文件。

    这是什么原因呢?我们仔细分析错误信息,说是“超过了最大请求长度”。

    原来是有最大长度限制!那应该在哪里设置可以上传更大的文件呢?

    通过研究,可以修改web.config增大可上传文件的大小限制。同时还可以设置最大执行时间。代码如下:

    <httpRuntime maxRequestLength="204800" executionTimeout="600"/>

    上述代码maxRequestLength的单位是KB,204800即是200MB。executionTimeout的单位是秒。

    通过上述设置,FileUpload就可以上传超过4m大文件了。

    你可能还不明白httpRuntime的设置代码该插入到web.config哪个地方,如果放错了,可能会导致web.config配置文件失效,从而影响网站的正常运行。请参考文章《httpRuntime代码放在web.config哪里?深度了解httpRuntime》。

    修改web.config后上传大于30M的文件失败

    通过上面介绍的方法,可以上传超过4m的大文件了,但是当上传大于30m的文件时,却又提示失败了!

    这时好像httpRuntimemaxRequestLength设置已经无效了。这又是什么原因呢?

    原来,IIS本身有请求长度限制!这时我们可以修改IIS配置来解决这个问题。

    首先,打开IIS,如下图

    接下来,选择自己的网站,停止,然后选中自己的站点,并双击“请求筛选”。

    双击请求筛选之后,看到右边操作中“编辑功能设置”,点击“编辑功能设置”,打开界面

    设置请求限制

    在弹出的页面中,我们看到默认请求限制正是30M,这时我们可以它改为更大的数字例如300M(300000000)以满足自己的要求,根据自己的需求设置,我这里设置102400000

    请注意,修改了IIS的“请求筛选”后,web.config里同样要设置httpRuntimemaxRequestLength的值大于30m。

    到了这里是不是以为已经完成了呢,开心ing(*^▽^*)

    不不不,其实还有

    最后一个坑

    添加system.webServer节点 修改服务器允许最大长度-requestLimits maxAllowedContentLength="1073741824"

    <configuration>
      <system.webServer>
        <security>
          <requestFiltering>
            <!--修改服务器允许最大长度-->
            <requestLimits maxAllowedContentLength="1073741824"/>
          </requestFiltering>
        </security>
      </system.webServer>
    </configuration>

    这个是我忘记设置的一个项,导致我浪费了一天时间,在纠结为何大文件上传就是不行,该设置的已经设置了还是不行,都怪自己太粗心了,哎呀ε=(´ο`*)))

    ok,到这里是真的完成了,整个过程很坎坷,一波三折,希望看到我这篇文章的朋友们,以后少走弯路哈~

    有疑问有建议的欢迎留言指导~

  • 相关阅读:
    Eclipse修改背景颜色(豆沙绿)
    项目导入时报错:The import javax.servlet.http.HttpServletRequest cannot be resolved
    jdk1.7 环境变量配置
    Maven的安装、配置及使用入门
    tomcat端口作用
    《Maven实战》
    Maven 详解
    遍历Map的四种方法
    遍历properties文件
    题库终结
  • 原文地址:https://www.cnblogs.com/guhuazhen/p/12073770.html
Copyright © 2020-2023  润新知