Winform文件下载之WebClient
最近升级了公司内部使用的一个下载小工具,主要提升了下面几点:
1. 在一些分公司的局域网中,连接不上外网
2. 服务器上的文件更新后,下载到的还是更新前的文件
3. 没有下载进度提示
4. 不能终止下载
下面和大家分享一些心得。
鉴于各种复杂的网络环境,笔者决定采用不同的编程接口进行下载尝试,以增加程序的可用性。
这里仅介绍使用WebClient的方法。博文中主要介绍思路和关键代码,完整的demo附在文末。
使用代理访问网络
很多公司的员工都是通过公司设置的代理上网的。通过代理上网主要是方便公司进行各种的管制,当然也能实现一些特殊的功能… 不过这会给我们的程序访问网络带来一些问题。
其实,WebClient中的API已经很智能了,比如我们创建的HttpWebRequest对象,它自带一个Proxy属性。也就是说,WebHttpRequest默认会使用找到的代理。这很棒,也能处理很多情况了。可是如果这个默认的代理需要验证域用户的身份信息,这时使用WebHttpRequest访问网络就可能失败。此时查看 Proxy. Credentials属性,发现它是null.
从WebClient的API中是可以取到系统默认的Credentials的,只是不太清楚为什么Proxy.Credentials属性默认没有设置为这个值。我们自己设置下就可以了。
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
但实际的网络环境可能会更复杂,需要用户来指定联网的代理,并同时指定联网所需的Credentials。写法如下:
myProxy = new WebProxy(“proxyAddress”); myProxy.Credentials = new NetworkCredential(ProxyUserName, ProxyUserPasswd, DomainName);
克服缓存
缓存可谓无处不再,在服务器端CDN会有缓存,在客户端的代理层也会有缓存。所以经常出现的问题是:服务器上的文件明明更新了,还是会有一些客户下载到旧文件。我们先来处理客户端的缓存问题。
HttpWebRequest的CachePolicy.Level属性就是设置缓存策略的,只是它的默认值是 BypassCache. 我们把它改为 Reload就行了:
request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.Reload);
接下是服务器端的缓存问题。
现在大家好像都在使用CDN,可在使用中经常发现CDN端的缓存更新有问题。在网上查了查也没有什么好的解决办法,不过倒是有一个很好的workaround,就是在请求中添加一个随机的字符串作为参数。
Random rdm = new Random(); string s = rdm.Next().ToString(); myUrl += "?" + s;
需要注意的是,关于缓存,一定要使用符合当前用例的策略,且不可搞一刀切。
更友好的下载过程
使用滚动条显示下载进度,显示实时的下载速度,允许用户取消下载
下面是下载用的核心代码,我们把它分为计算下载百分比和计算当前下载速度分别介绍。
// 获得下载文件的长度
double contentLength = DownloadManager.GetContentLength(myHttpWebClient);
byte[] buffer = new byte[BufferSize];
long downloadedLength = ;
long currentTimeSpanDataLength = ;
int currentDataLength;
while ((currentDataLength = stream.Read(buffer, , BufferSize)) > && !this._cancelDownload)
{
fileStream.Write(buffer, , currentDataLength);
downloadedLength += (long)currentDataLength;
currentTimeSpanDataLength += (long)currentDataLength;
int intDownloadSpeed = ;
if (this._downloadStopWatch.ElapsedMilliseconds > )
{
double num5 = (double)currentTimeSpanDataLength / 1024.0;
double num6 = (double)this._downloadStopWatch.ElapsedMilliseconds / 1000.0;
double doubleDownloadSpeed = num5 / num6;
intDownloadSpeed = (int)Math.Round(doubleDownloadSpeed, );
this._downloadStopWatch.Reset();
this._downloadStopWatch.Start();
currentTimeSpanDataLength = ;
}
double doubleDownloadPersent = 0.0;
if (contentLength > 0.0)
{
doubleDownloadPersent = (double)downloadedLength / contentLength;
}
}
在下载的过程中计算下载百分比
首先需要从http请求中获得要下载文件的长度,细节请参考本文所配demo.
double contentLength = DownloadManager.GetContentLength(myHttpWebClient);
每从文件流中读取一次数据,我们知道读了多少个字节(currentDataLength),累计下来就是当前已经下载了的文件长度。
downloadedLength += (long)currentDataLength;
然后做个除法就行了:
doubleDownloadPersent = (double)downloadedLength / contentLength;
计算实时的下载速度
对于当前的下载速度,我们计算过去的一段时间内下载下来的字节数。时间段可以使用StopWatch来获得,我选择的时间段要求大于800毫秒。
if (this._downloadStopWatch.ElapsedMilliseconds > )
{
/***********************************/
// 计算上一个时间段内的下载速度
double num5 = (double)currentTimeSpanDataLength / 1024.0;
double num6 = (double)this._downloadStopWatch.ElapsedMilliseconds / 1000.0;
double doubleDownloadSpeed = num5 / num6;
/***********************************/
intDownloadSpeed = (int)Math.Round(doubleDownloadSpeed, );
// 本次网速计算完成后重置时间计时器和数据计数器,开始下次的计算
this._downloadStopWatch.Reset();
this._downloadStopWatch.Start();
currentTimeSpanDataLength = ;
}
事实上每次计算下载速度的时间段长度是不固定的,但这并不影响计算结果,我只要保证距离上次计算超过了800毫秒就行了。
允许用户取消下载
对于一个执行时间比较长的任务来说,不允许用户取消它是被深恶痛绝的!尤其是网速不太好的时候。所以我们需要给用户一个选择:可以痛快(而不是痛苦)的结束当前的旅程。
而这一切对我们来说又是那么的简单!
while ((currentDataLength = stream.Read(buffer, , BufferSize)) > && !this._cancelDownload){}
当从数据流中读取数据时,我们检查用户是不是按下了“取消”按钮,就是这里的 this._cancelDownload 变量。如果它是 true就结束当前的下载。
至此,把用户抱怨最多的几个点都搞定了。其实也没有增加多少代码,并且每个知识点看起来都是那么的细微。但很明显的提高了用户的使用体验。这也给我们带来了一些启发,完成主要功能可能只是工作中的一部分,另外的一些工作可能并不是那么明显,需要我们不断的体会,发觉…
Winform文件下载之WebClient的更多相关文章
- Winform文件下载之WinINet
在C#中,除了webclient我们还可以使用一组WindowsAPI来完成下载任务.这就是Windows Internet,简称 WinINet.本文通过一个demo来介绍WinINet的基本用法和 ...
- winform客户端利用webClient实现与Web服务端的数据传输
由于项目需要,最近研究了下WebClient的数据传输.关于WebClient介绍网上有很多详细介绍,大概就是利用WebClient可以实现对Internet资源的访问.无外乎客户端发送请求,服务端处 ...
- winform下通过webclient使用非流方式上传(post)数据和文件
这两天因为工作的需要,需要做一个winform上传数据到服务器端的程序.当时第一个想法是通过webservice的方式来实现,后来觉得麻 烦,想偷懒就没有用这样的方式,http的post方式变成了第一 ...
- Winform文件下载之断点续传
在本系列的前两篇文章中,分别向大家介绍了用于完成下载任务的 WebClinet 和 WinINet 的基本用法和一些实用技巧. 今天来为大家讲述下载过程中最常遇到的断点续传问题. 首先明确一点,本文所 ...
- webclient下载文件 带进度条
private void button1_Click(object sender, EventArgs e) { doDownload(textBox1.Text.Trim()); } private ...
- C# 文件下载 : WebClient
最近更新了一个下载小工具,主要提升了下面几点: 1. 在一些分公司的局域网中,连接不上外网 2. 服务器上的文件更新后,下载到的还是更新前的文件 3. 没有下载进度提示 4. 不能终止下载 下面和大家 ...
- c# WebClient文件下载
public void HttpDownload(string url, string path, ResourceType type) { using (var client = new WebCl ...
- 基于Winform、WPF等的客户端文件下载
有时候,我们用C#写一些客户端应用程序需要从服务器下载一些资源,如图片.dll.配置文件等.下面就来说一下,在Winform及WPF中如何下载文件. 我们的资源大多放在自己的网站上,或者从其他网站下载 ...
- 使用WebClient类对网页下载源码,对文件下载保存及异步下载并报告下载进度
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAx4AAAI7CAIAAADtTtpYAAAgAElEQVR4nO3dX6xlV33Y8f3UJFUqHq
随机推荐
- Xilinx的约束文件
FPGA中有三种约束文件,分别是用户设计文件(.ucf文件),网表约束文件(.NCF文件)与物理约束文件(.PCF文件). 在设计阶段,需要硬件描述文件与UCF文件,经过综合后生成NCF文件,最后得到 ...
- Extjs 表单验证后,几种错误信息展示方式
今天要求对form表单验证,进行系统学习一下,故做了几个示例: Ext.onReady(function(){ var panel=Ext.create('Ext.form.Panel' ...
- 使用sklearn进行集成学习——理论
系列 <使用sklearn进行集成学习——理论> <使用sklearn进行集成学习——实践> 目录 1 前言2 集成学习是什么?3 偏差和方差 3.1 模型的偏差和方差是什么? ...
- 【解题报告】BZOJ2550: [Ctsc2004]公式编辑器
题意:给定一个可视化计算器的操作序列,包括插入数字.字母.运算符.分数.矩阵以及移动光标.矩阵插入行.插入列,输出操作序列结束后的屏显(数学输出). 解法:这题既可以用来提升OI/ACM写大代码模拟题 ...
- XML转JSON
Step 1 : 下载 java-json.jar http://www.java2s.com/Code/JarDownload/java/java-json.jar.zip Step 2: 增加 j ...
- java.lang.RuntimeException: Method setUp in android.test.ApplicationTestCase not mocked. See http://g.co/androidstudio/not-mocked for details.
解决: build.gradle里加入: android { testOptions { unitTests.returnDefaultValues = true } }
- [原] XAF 添加日期筛选下拉选择
1.ListView 添加日期筛选下拉选择,选择指定,可指定日期范围 2.Code using DevExpress.Data.Filtering; using DevExpress.ExpressA ...
- PhoneGap(二维码扫描 )
关于 phoneGap 如何做 二维码扫描 1. 先配置好, 环境 http://coenraets.org/blog/cordova-phonegap-3-tutorial/http: ...
- php composer使用经验
1.使用composer引用了一个包,但是这个包没有使用命名空间,在项目中该如何使用这个包? 编辑composer.json文件 "autoload":{ "files& ...
- AngularJs 与Jquery的对比分析,超详细!
闲来无事,在网上发现了一篇对比AngularJs和Jquery的文章.恰好最近自己也在研究AngularJs.特此收藏.需要的朋友可以参考. 原问题:假如我熟悉利用jQuery去开发客户端应用,那么我 ...