分享一篇關於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("\r\n--" + strBoundary + "\r\n");
            //請求的頭部信息
            StringBuilder sb = new StringBuilder();
            sb.Append("--");
            sb.Append(strBoundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"");
            sb.Append("file");
            sb.Append("\"; filename=\"");
            sb.Append(saveName);
            sb.Append("\";");
            sb.Append("\r\n");
            sb.Append("Content-Type: ");
            sb.Append("application/octet-stream");
            sb.Append("\r\n");
            sb.Append("\r\n");
            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,到這里是真的完成了,整個過程很坎坷,一波三折,希望看到我這篇文章的朋友們,以后少走彎路哈~

有疑問有建議的歡迎留言指導~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM