c#在WinForm下使用HttpWebRequest上传文件并显示进度

摘要:
本打算使用WebClient方法,但在实施此方法后,进度条将在短时间内达到最大值。完成传输需要一段时间。如果文件太大,将发生错误。后来,我们了解到WebClient实际上是在将一个完整的文件加载到内存后开始上传的。难怪会出现以前的问题。我不得不参考许多文章。一位外国人的一篇文章给了我很多启发。它是使用HttpWebRequest方法实现的。

这段时间因项目需要,要实现WinForm下的文件上传,个人觉得采用FTP方法太麻烦,还得配置FTP服务器,要通过防火墙也是一个麻烦。本来打算采用WebClient方法,但是采用这个方法实现后,进度条很短时间后就达到最大值,要等待一段时间才能传送完毕,要是文件太大(我这里测试约100M),会出现错误。后来才知道,原来WebClient是在加载完整个文件到内存后才真正开始上传,怪不得会出现前面的问题了。不得已参考了很多文章,老外的一个文章对我启发很大(http://blogs.msdn.com/johan/archive/2006/11/15/are-you-getting-outofmemoryexceptions-when-uploading-large-files.aspx),是采用HttpWebRequest方法实现的。废话少说,开始进入正题。实现过程如下:

在WinForm里面调用下面的方法来上传文件:

// <summary>
        /// 将本地文件上传到指定的服务器(HttpWebRequest方法)
        /// </summary>
        /// <param name="address">文件上传到的服务器</param>
        /// <param name="fileNamePath">要上传的本地文件(全路径)</param>
        /// <param name="saveName">文件上传后的名称</param>
        /// <param name="progressBar">上传进度条</param>
        /// <returns>成功返回1,失败返回0</returns>
        private 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.Method = "POST";

            //对发送的数据不使用缓存
            httpReq.AllowWriteStreamBuffering = false;

            //设置获得响应的超时时间(300秒)
            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;

                //每次上传4k
                int bufferLength = 4096;
                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;
                    lblTime.Text = "已用时:" + second.ToString("F2") + "秒";
                    if (second > 0.001)
                    {
                        lblSpeed.Text = " 平均速度:" + (offset / 1024 / second).ToString("0.00") + "KB/秒";
                    }
                    else
                    {
                        lblSpeed.Text = " 正在连接…";
                    }
                    lblState.Text = "已上传:" + (offset * 100.0 / length).ToString("F2") + "%";
                    lblSize.Text = (offset / 1048576.0).ToString("F2") + "M/" + (fileLength / 1048576.0).ToString("F2") + "M";
                    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")
                {
                    returnValue = 1;
                }
                else if (sReturnString == "Error")
                {
                    returnValue = 0;
                }

            }
            catch
            {
                returnValue = 0;
            }
            finally
            {
                fs.Close();
                r.Close();
            }

            return returnValue;
        }

参数说明如下:

address:接收文件的URL地址,如:http://localhost/UploadFile/Save.aspx

fileNamePath:要上传的本地文件,如:D:\test.rar

saveName:文件上传到服务器后的名称,如:200901011234.rar

progressBar:显示文件上传进度的进度条。

接收文件的WebForm添加一个Save.aspx页面,Load方法如下:

protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.Files.Count > 0)
            {
                try
                {
                    HttpPostedFile file = Request.Files[0];
                    string filePath = this.MapPath("UploadDocument") + "\" + file.FileName;
                    file.SaveAs(filePath);
                    Response.Write("Success\r\n");
                }
                catch
                {
                    Response.Write("Error\r\n");
                }
            }
 

同时需要配置WebConfig文件的httpRuntime 如下:

<httpRuntime maxRequestLength="102400"  executionTimeout="300"/>

不能的话最大只能上传4M了。要是想上传更大的文件,maxRequestLength,executionTimeout设置大些,同时WinForm下的代码行

//设置获得响应的超时时间(300秒)
            httpReq.Timeout = 300000;

也要修改,另外别忘了看看IIS的连接超时是否设置为足够大。

一切都配置好了,运行效果如下:

为了解决这个问题,我查看了很多文章,记于此,以后遇到同样的问题有个查找的地方。

免责声明:文章转载自《c#在WinForm下使用HttpWebRequest上传文件并显示进度》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇(转)C语言中格式化日期时间asctime()函数详细讲解JS插件:ECharts-数据图表化-事件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

winform程序登陆后关闭登录窗体

用winform做程序的时候,我们一般都是在Program先启动登录窗体,然后登录成功后才创建主窗体,结果这就导致了登录窗体无法关闭 所以如果我们不在Program的程序入口先创建登录窗体的话就能完美实现登录成功后关闭登录窗体的功能了,直接贴代码 usingSystem; usingSystem.Collections.Generic; usingSyst...

winform中如何在TextBox中只能输入数字(可以带小数点)

可以采用像web表单验证的方式,利用textbox的TextChanged事件,每当textbox内容变化时,调用正则表达式的方法验证,用一个label在text后面提示输入错误,具体代码如下: private void textBox1_TextChanged(objectsender, EventArgs e) {...

winform项目笔记:

餐饮管理系统:三层架构模式。 Modal,bll,dal,UI,Common.   知识点:     using语句释放的是非托管的资源。托管的资源会有CLR自动释放。     DataGridView控件:      dataGridView1.AutoGenerateColumns = false; 把自动生成列关掉。   事件其实也是一个方法,想要调用...

Spring Boot + thymeleaf 实现文件上传下载

参考博客:https://juejin.im/post/5a326dcaf265da431048685e 技术选型:spring boot 2.1.1+thymeleaf+maven 码云地址:https://gitee.com/ZhangShunHai/upload 项目截图:...

C#WinForm,TCP调试工具

Server端配置 参考代码 1)设置基本参数 /// <summary> ///以本机作测试 /// </summary> private IPAddress serverIP = IPAddress.Parse("192.168.0.105"); /// <summary> ///完整终端地址 ///...

【WinForm程序】注册热键快捷键切换

重写DefWndProc事件 #region Window 消息捕获 const int WM_COPYDATA = 0x004A; public structCOPYDATASTRUCT { publicIntPtr dwData; public i...