[转]数据下载(八)

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


namespace prjDownLoad
{
    class Program
    {
        //添加一个AutoResetEvent
        //这是一个信号机
        static AutoResetEvent are = new AutoResetEvent(false);
        static void Main(string[] args)
        {
            //Version8.0
            //将下载数据放入线程池中。
            ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadData));
            //等着,直到有人通知说俺可以继续。
            are.WaitOne();
            Console.WriteLine("俺可以干其他的活了。");
            //去掉俺最不喜欢的Console.ReadLine
            //程序运行到这里为什么需要Console.ReadLine?
            //因为现在如果直接结束主线程,那么异步回来的数据
            //就没人接收了。
            //为什么要去掉Console.ReadLine呢?
            //你以为谁都像你一样的做的都是控制台应用程序?!
            //Console.ReadLine();
        }
        //把这个方法加一个object参数,这是WaitCallback要求的
        static 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>
        static 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);
        }

        /// <summary>
        /// 一次读取完成后调用的方法
        /// </summary>
        /// <param name="result"></param>
        static void ReadCallBack(IAsyncResult result)
        {
            //先把实体类对象从AsyncState中拿出来。
            DownloadInfo di = result.AsyncState as DownloadInfo;
            //看看这次读取完成后读取了多少玩意。
            //具体的内容在di的Buffer中放着呢。
            int x = di.ReadSt.EndRead(result);
            //如果x大于零,那么还有的读。
            if (x > 0)
            {
                //把读取到的数据,写入写入流中
                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();

                //读取完成后,再通知其他线程
                //可以做其他的工作了。
                are.Set();
            }
        }
    }


    /// <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; }
        }
    }
}

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

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