1.实现功能:

  多文件下载.添加下载路径后开始下载文件,实时显示下载进度和下载速度,还可以显示全局速度.可以断点续传.

2.效果截图:

3.技术细节:

 1) C#如何下载文件.

     在Syetem.Net命名空间下,有一个WebClient类,可以很轻松的实现下载文件功能.实例化该类后,用DownloadFile方法即可以下载文件.该类有一个DownloadProgressChanged事件,用这个事件就可以完成进度条功能了.该类还有一个CancelAsync方法,可以实现下载中的暂停功能.

  我们还可以用更底层点的技术.HttpWebRequest类可以发起一个Http请求,请求成功会访问输出的HttpWebResponse,通过其的GetResponse方法可以得到服务器的输出流,再用自己喜欢的方式写入到本地.

2) 如何开始下载,暂停,断点续传,监视进度

  先说下怎么断点续传.Http请求头里有个很有用的信息"Range".普通的请求头里不带这个信息,服务器会将整个文件输出给我们.当我们指定一个整数值时,服务器会将该值做为一个偏移量,再读取文件输出给我们.因此,下载功能类需要保存一个已下载字节的属性或字段,当暂停后再次请求下载时,将该字段写入HTTP请求的头信息里即可.

  WebClient类提供了DownloadFileAsync方法,可以开始请求文件并下载.提供了CancelAsync方法,可以取消一次请求.提供了DownloadProgressChanged事件,可以监视进度.这个类可以说提供了大部分的功能给我们做简单的应用,十分轻巧方便.WebClient也可以直接操作header信息,方便我们写入range.可惜的是,每次调用DownloadFile方法,本地文件会被重写,不能保存以前下载的信息,因此不能实现断点续传.

  HttpWebRequest类没有提供上面那么多的属性和方法,我们可以通过自己的方式来实现这些功能.下面是截取的部分代码:

        /// <summary>
        /// 开始下载
        /// </summary>
        public void StartDownload()
        {
       //暂停功能只需要将此属性设置为false,则下面的下载循环会跳出 IsDownloading = true; HttpWebRequest request = (HttpWebRequest)FileWebRequest.Create(this.DownloadUrl); if (DownloadBytes > 0) {
         //此处写入range,实现断点续传 request.AddRange(DownloadBytes); } request.BeginGetResponse(ar => { var response = request.EndGetResponse(ar); if (this.TotalBytes == 0) this.TotalBytes = response.ContentLength; using (var writer = new FileStream(this.FileName, FileMode.OpenOrCreate)) { using (var stream = response.GetResponseStream()) { while (IsDownloading) { byte[] data = new byte[readBytes]; int readNumber = stream.Read(data, 0, data.Length); if (readNumber > 0) { writer.Write(data, 0, readNumber);
                   //此处记录已经下载的字节数,也做为进度条功能的实现代码 this.DownloadBytes += readNumber; } if (this.DownloadBytes == this.TotalBytes) {
                   //通知下载已完成 Complete(); } } } } }, null); }

 3) 如何监视即时下载速度

  大家观察下迅雷的即时速度,就会发现变化时间是很有规律的.因此我们只需要在全局放一个Timer,每过一段时间扫描一次下载列表,统计每个文件本次扫描到上次扫描的下载字节数,再除以间隔时间,那么每个文件的下载速度就得到了,文件下载速度之和就是全局速度.

 4) 以上功能在WPF中的整合

      由于涉及到大量与UI的交互,因此我采用了MVVM模式,尽量使逻辑与UI解耦.可以参看下面提供的源码

4. 实现代码:

    点击此处下载 

  可以说毫无任何技术亮点,只是采用了MVVM模式实现,不会MVVM的可以参考下.欢迎大家拍砖吐槽.

  注意:此代码我是在VS2012下编辑,本地尝试VS2010 SP1可以正常打开.只花了1个小时左右,只是实现了添加下载文件,全部开始,全部暂停功能.验证路径有效性,下载过程中的错误,删除文件,打开文件,指定下载路径等等暂时没有实现.

5. 吐槽:

    这里说下为什么闲得蛋疼的写这么个东西.

    话说楼主8月刚入职现在的公司,本周2时另一个公司的HR在QQ叫我去面试,说得天花乱坠的,什么给自己个机会啊,目前试用期正好多个选择啊扒拉扒拉扒拉.楼主看了下他们的招聘介绍,主要是做WPF开发,HR也说要熟悉MVVM,楼主正好上半年又专门研究了WPF.所以只能怪楼主忘了吃脑残片,居然就答应下来.然后周5请了半天假屁颠屁颠的跑去面试.

  一过去就让我机试.我对机试倒不排斥,从来敲代码速度都是惊人的快.看了题吧,要做的也很简单,然后就啪啪啪的敲.其中1个就是下载功能.原题是:"从路径XXX下载一个文件到本地再打开,显示下载进度和速度".楼主只看到进度两字(太马虎了),直接用WebClient实现,没超过30行代码.40多分钟就全部敲完了,然后过来3个搞技术的站我背后叫我讲解代码.讲到下载文件那里就杯具了吧,没有显示速度.

    然后我也挺不好意思的,实在是太马虎了.我就巴拉巴拉的说思路呗,要是平均速度,就用个Stopwatch记录开始到结束的时间,一除就行了.要是即时速度,像上面用个timer定时来扫.

    其中一个就问我,再给你5分钟你能把这个实现么?这就让我很不爽,思路都有了非要我敲代码?当别人面啪啪啪的敲代码就好像当别人面"啪啪啪"一样,不舒服的好吧!

    接着又问我,要是改下需求,提供下断点续传能实现不?这下我彻底火了,我整天面对客户要随时改需求就算了,你丫的就这么一个面试还随便改需求?我就很为难的说,前面的实现思路错了,要实现这个就得大改.

    另外一个又说了,给你30分钟把它改好吧!我这个去哦!我们公司的客户改需求,都小心翼翼的巴结着,问:dear啊,simple改动啦,时间你们make decision啦.你们觉得面试者就低人一等嘛,规定时间改不完就out了?我简直无法,无力说什么了.然后我当场就大声拒绝了,估计他们看我面色不善,赶紧说今天就到这,然后就散了.

    回家的地铁上,心里越来越不是滋味.我这到底是为了什么?我在一家外企,薪水和福利都不错,公司处在IT开发圈,周围环境很好,外企里面英语提升也快.居然白白的请半天假,去这么家公司面试,WPF的职位,就只要会做点布局,会点断点续传之类的小技术,就能开发了么?

    我理想中的WPF面试,有很多东西可以交流啊!依赖对象和依赖属性,路由事件,模板和样式,资源,绑定等等基础的东西不交流么?再有,CLR,IL,反射,泛型,委托,GC,多线程等C#的东西不交流么?我在那待了1个半小时,这么宝贵的1个半小时我就写了2个xaml的布局,敲了几行简单得不能再简单的代码.

    回家里路上,先是修路堵了2个小时,然后小区又停电,发现只要人倒霉,那么倒霉的事总是接二连三,害得我晚饭都没心情吃.今天下午来电,先把QQ挂上,关注下钓鱼岛局势,然后把项目建起,一个人对着墙啪啪啪得敲代码,把所谓的断点续传简单实现了.然后又花1个多小时来写这么一篇博客.

    以后再遇到要我上机的,不管是上计算机计算器手机小霸王,我一律不去了!

posted on 2012-09-22 20:11  烟灰灰  阅读(5220)  评论(22编辑  收藏  举报