C# 非同步下載檔案

來源:互聯網
上載者:User

在C#當中,利用WebClient這個核心類,可以輕易的打造一個下載器。但是這裡想要強調的是,我們用的是非同步作業。所謂非同步,是相對於同步的概念而言的。比如Web中的Ajax就是基於非同步。它能夠提供良好的使用者體驗,讓使用者在進行操作時,不感覺到“卡”(不阻塞UI線程),能夠同時進行其它的操作並能夠隨意的切換到任務介面。在下載檔案時,如果檔案過大,我們用同步的下載方式進行下載會感覺程式“假死”,其實程式在後台不斷的運行,但我們看不到下載的過程。所以這時候使用非同步方法呼叫能夠有效解決這個問題。

先看一下程式的介面:


實現上面的操作很簡單,只需要幾行代碼就可以搞定。

        private void button1_Click(object sender, EventArgs e)        {            using (WebClient client = new WebClient())            {                client.DownloadFileAsync(new Uri(this.textBox1.Text.Trim()),Path.GetFileName(this.textBox1.Text.Trim()));                client.DownloadProgressChanged += client_DownloadProgressChanged;                client.DownloadFileCompleted += client_DownloadFileCompleted;            }        }        void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)        {            this.label1.Text = string.Format("當前接收到{0}位元組,檔案大小總共{1}位元組", e.BytesReceived, e.TotalBytesToReceive);            this.progressBar1.Value = e.ProgressPercentage;        }        void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)        {            if (e.Cancelled)            {                MessageBox.Show("檔案下載被取消", "提示", MessageBoxButtons.OKCancel);            }            this.progressBar1.Value = 0;            MessageBox.Show("檔案下載成功", "提示");        }
我們只需要在textbox中填入檔案的地址,比如迅雷的:http://dlsw.baidu.com/sw-search-sp/soft/ca/13442/Thunder_dl_7.9.18.4706Preview.2205245239.exe,就可以用上面的代碼進行下載了。

在C#當中,還可以利用HttpWebRequest進行檔案的非同步下載。下面的代碼可能稍微有點複雜,但是可以協助我們深入理解“非同步“操作的過程。

我們先定義一個類,用於儲存操作的狀態:

    /// <summary>    /// 請求狀態    /// </summary>    public class RequestState    {        /// <summary>        /// 緩衝區大小        /// </summary>        public int BUFFER_SIZE { get; set; }        /// <summary>        /// 緩衝區        /// </summary>        public byte[] BufferRead { get; set; }        /// <summary>        /// 儲存路徑        /// </summary>        public string SavePath { get; set; }        /// <summary>        /// 請求流        /// </summary>        public HttpWebRequest Request { get; set; }        /// <summary>        /// 響應流        /// </summary>        public HttpWebResponse Response { get; set; }        /// <summary>        /// 流對象        /// </summary>        public Stream ResponseStream { get; set; }        /// <summary>        /// 檔案流        /// </summary>        public FileStream FileStream { get; set; }    }
在一個Button的Click事件下,鍵入如下代碼:

            //下載檔案的url            string url = this.textBox1.Text.Trim();            //建立一個初始化請求對象            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));            //設定下載相關參數            RequestState requestState = new RequestState();            requestState.BUFFER_SIZE = 1024;            requestState.BufferRead = new byte[requestState.BUFFER_SIZE];            requestState.Request = request;            requestState.SavePath = Path.Combine("D:\\", Path.GetFileName(url));            requestState.FileStream = new FileStream(requestState.SavePath, FileMode.OpenOrCreate);            //開始非同步請求資源            request.BeginGetResponse(new AsyncCallback(ResponseCallback), requestState);
我們可以看到,非同步操作方法一般都是以Begin開頭的BeginGetResponse,我們平時用的比較多的同步方法直接使用GetResponse。另外AsyncCallback是一個委託,前面講過,它裡面的參數是一個方法,我們起名為ResponseCallback,並且把requestState作為參數傳遞過去。

接下來就可以看一下ResponseCallback方法:

        /// <summary>        /// 請求資源方法的回呼函數        /// </summary>        /// <param name="asyncResult">用於在回呼函數當中傳遞操作狀態</param>        private void ResponseCallback(IAsyncResult asyncResult)        {            RequestState requestState = (RequestState)asyncResult.AsyncState;            requestState.Response = (HttpWebResponse)requestState.Request.EndGetResponse(asyncResult);            Stream responseStream = requestState.Response.GetResponseStream();            requestState.ResponseStream = responseStream;            //開始非同步讀取流            responseStream.BeginRead(requestState.BufferRead, 0, requestState.BufferRead.Length, ReadCallback, requestState);        }
我們可以看到,回呼函數裡面又有一個非同步作業。它的任務是對響應流非同步讀取到緩衝區當中。

再進一步,看一下ReadCallback回呼函數。

        /// <summary>        /// 非同步讀取流的回呼函數        /// </summary>        /// <param name="asyncResult">用於在回呼函數當中傳遞操作狀態</param>        private void ReadCallback(IAsyncResult asyncResult)        {            RequestState requestState = (RequestState)asyncResult.AsyncState;            int read = requestState.ResponseStream.EndRead(asyncResult);            if (read > 0)            {                //將緩衝區的資料寫入該檔案流                requestState.FileStream.Write(requestState.BufferRead, 0, read);                //開始非同步讀取流                requestState.ResponseStream.BeginRead(requestState.BufferRead, 0, requestState.BufferRead.Length, ReadCallback, requestState);            }            else            {                requestState.Response.Close();                requestState.FileStream.Close();            }        }

這裡面是真正的將流寫入檔案的過程,並且用BeginRead方法遞迴的寫入檔案流直到檔案完全寫好為止(完全下載到本地)。

上面我參考了官方網站上面的代碼,可以在這裡查詢到:BeginGetResponse。這是一個經典的非同步作業的例子,希望大家能夠好好理解。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.