[转]数据下载(十一)

简单封装:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;

namespace prjDownLoad
{
    class Program
    {
        static void Main(string[] args)
        {
            //信号机
            AutoResetEvent are = new AutoResetEvent(false);
            //实例化下载工具
            DownloadUtil du = new DownloadUtil();
            du.are = are;
            //订阅事件
            du.ReadCompleted += new ReadCompletedHandler(du_ReadCompleted);
            du.ReadProgress += new ReadProgressHandler(du_ReadProgress);
            //加入线程池中
            ThreadPool.QueueUserWorkItem(new WaitCallback(du.DownloadData));
            //等待通知信号
            are.WaitOne();
        }

        static void du_ReadProgress(int x)
        {
            Console.WriteLine("下载了{0}字节",x);
        }

        static void du_ReadCompleted()
        {
            Console.WriteLine("下载完成了。");
        }
    }
}

using System;
using System.Collections.Generic;
using System.Text;

namespace prjDownLoad
{
    //读取完成委托
    public delegate void ReadCompletedHandler();
}
using System;
using System.Collections.Generic;
using System.Text;

namespace prjDownLoad
{
    //读取过程委托
    public delegate void ReadProgressHandler(int x);
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace prjDownLoad
{
    /// <summary>
    /// 下载信息实体类
    /// </summary>
    [Serializable]
    public class DownloadInfo
    {
        Stream readSt;
        /// <summary>
        /// 读取数据的流
        /// </summary>
        public Stream ReadSt
        {
            get { return readSt; }
            set { readSt = value; }
        }

        Stream writeSt;
        /// <summary>
        /// 写入数据的流
        /// </summary>
        public Stream WriteSt
        {
            get { return writeSt; }
            set { writeSt = value; }
        }

        byte[] buffer = new byte[1024];
        /// <summary>
        /// 缓冲字节数组,用来存储从流中读取的数据的容器
        /// </summary>
        public byte[] Buffer
        {
            get { return buffer; }
            set { buffer = value; }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.IO;

namespace prjDownLoad
{
    public class DownloadUtil
    {
        //添加一个AutoResetEvent
        //这是一个信号机
        public AutoResetEvent are;
        //读取完成事件
        public event ReadCompletedHandler ReadCompleted;
        //读取过程事件
        public event ReadProgressHandler ReadProgress;
        //把这个方法加一个object参数,这是WaitCallback要求的
        public void DownloadData(object obj)
        {
            //不光WebResponse的获得使用异步方式
            //连读取数据都使用异步方式。
            //创建WebRequest对象
            WebRequest wr = WebRequest.Create("http://blog.sina.com.cn/dalishuishou");
            //开始异步地获取回应对象
            //如果有了回应对象,那么把过程交给GetResponseCallBack去处理
            wr.BeginGetResponse(new AsyncCallback(GetResponseCallBack), wr);
        }

        /// <summary>
        /// 当有回应对象时调用这个方法来处理。
        /// </summary>
        /// <param name="result"></param>
        void GetResponseCallBack(IAsyncResult result)
        {
            //拿到那个请求对象
            WebRequest wr = result.AsyncState as WebRequest;
            //如果回应回完了,那么拿到回应对象
            WebResponse wsp = wr.EndGetResponse(result);
            //从回应中拿到流
            Stream st = wsp.GetResponseStream();
            //输出的文件流,此处也可替换为其他的流。
            FileStream fs = new FileStream("c:\\ee.txt", FileMode.Create, FileAccess.Write);
            //将异步操作过程中用到的信息封装为对象
            DownloadInfo di = new DownloadInfo();
            di.ReadSt = st;
            di.WriteSt = fs;
            //传入异步读取方法中
            //第一个参数:读取的内容放到啥地方。
            //第二个参数:从流的啥地方开始读取,一般从头开始,选择0。
            //第三个参数:读取多少数据,一般容器多大,就读取多少数据。
            //第四个参数:当读取完成后调用的方法,注意这个方法不是把所有数据都读取完成
            //            而是这一次读取完成后,比如这次只读取了1024字节,那么当读取了
            //            1024字节以后,就会完成一次,就会调用一次ReadCallBack方法。
            //第五个参数:读取完成过程中用到的参数。
            st.BeginRead(di.Buffer, 0, di.Buffer.Length, new AsyncCallback(ReadCallBack), di);
        }

        int count = 0;
        /// <summary>
        /// 一次读取完成后调用的方法
        /// </summary>
        /// <param name="result"></param>
        void ReadCallBack(IAsyncResult result)
        {
            //先把实体类对象从AsyncState中拿出来。
            DownloadInfo di = result.AsyncState as DownloadInfo;
            //看看这次读取完成后读取了多少玩意。
            //具体的内容在di的Buffer中放着呢。

            int x = di.ReadSt.EndRead(result);
            //如果x大于零,那么还有的读。
            if (x > 0)
            {
                count += x;
                //激发读取过程事件
                if (ReadProgress != null)
                {
                    ReadProgress(x);
                }
                //把读取到的数据,写入写入流中
                di.WriteSt.Write(di.Buffer, 0, x);
                //清输出缓冲区,把数据压过去。
                di.WriteSt.Flush();
                //到这儿应该还有的读,所以再读一回。
                //此处是递归了,再次调用这个方法自身。
                di.ReadSt.BeginRead(di.Buffer, 0, di.Buffer.Length, new AsyncCallback(ReadCallBack), di);
            }
            else//否则没的读了。
            {
                //关读取流
                di.ReadSt.Close();
                //关写入流
                di.WriteSt.Close();
                //激发读取完成事件
                if (ReadCompleted != null)
                {
                    ReadCompleted();
                }
                //读取完成后,再通知其他线程
                //可以做其他的工作了。
                are.Set();
            }
        }
    }
}

转摘自:http://blog.sina.com.cn/s/blog_49458c270100iouh.html

posted @ 2011-03-01 23:06  愤怒的熊猫  阅读(126)  评论(0编辑  收藏  举报