2017年9月30日 星期六

C# : 網路下載檔案之下載進度事件 event 方法

在上一個 C# : 網路下載檔案之下載進度委派方法 練習中,我們使用的委派型別,來做為通知使用者最新的下載進度,在這裡,我們將會使用 C# 的事件 Event,來做出相同效果的程式碼。
由於我們需要透過事件來回報處理進度,因此,我們需要客製化一個類別,用來處理這件需求,在這裡,我們需要在新建立的類別,讓他繼承 EventArgs 類別,在這個新的類別,DownloadFileEventArgs,我們新增一個屬性,用來說明處理進度百分比。
另外,對於 Task.Factory.StartNew,我們有做些調整,在這裡,我們將修飾詞 async 移除了,所以,現在的現在傳入的委派 Lambda 將會是:Task.Factory.StartNew(() => {...};由於沒有了 async 修飾詞,所以,在 Task.Factory.StartNew 引數用的委派方法,我們就要進行調整,把原先這個委派方法內有使用到 await 的地方,全部修改成為同步的執行方法;不過,在這裡,你不用擔心,因為我們使用了 Task.Factory.StartNew 啟動一個全新的工作,這個工作會使用 ThreadPool 執行緒集區內的一個執行緒來執行這個工作,所以,也是多工處理的作業。
當要進行回報處理進度事件的時候,我們需要呼叫這個方法:onProgress(this, new DownloadFileEventArgs() { Percent = percent });,在第二個引數,我們需要透過 DownloadFileEventArgs 產生的物件,將現在處理進度傳送到訂閱者的綁定方法中。
public class DownloadFileEventArgs : EventArgs
{
    public int Percent { get; set; }
}

public class DownloadFile
{
    public event EventHandler<DownloadFileEventArgs> OnProgress;
    //public string Url { get; set; } = "http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/js_api_reference.pdf";
    public string Url { get; set; } = "https://www.tutorialspoint.com/csharp/csharp_tutorial.pdf";
    public Task Download()
    {
        var task = Task.Factory.StartNew(() =>
        {
            int offset = 5120;
            int percent = 0;
            int currentDonload = 0;
            int getBytes;
            int lastPercent = -1;
            using (var client = new HttpClient())
            {
                using (var response = client.GetAsync(Url).Result)
                {
                    var total = int.Parse(response.Content.Headers.First(h => h.Key.Equals("Content-Length")).Value.First());
                    byte[] content = new byte[total+offset];
                    using (var stream = response.Content.ReadAsStreamAsync().Result)
                    {
                        var onProgress = OnProgress;
                        while ((getBytes = stream.Read(content, currentDonload, offset)) > 0)
                        {
                            currentDonload += getBytes;
                            percent = (int)((1.0 * currentDonload / total) * 100);
                            if (lastPercent != percent)
                            {
                                if (onProgress != null)
                                {
                                    onProgress(this, new DownloadFileEventArgs() { Percent = percent });
                                }
                                lastPercent = percent;
                            }
                        }
                    }
                }
            }
        });
        return task;
    }
}
現在,讓我們開始進行測試,我們同樣需要訂閱 OnProgress 的事件,不過,您會看到輸出結果卻是不太相同,這並不是我們使用事件的方式,你可以知道發生了甚麼問題以及差異在哪裡?
static async Task Main(string[] args)
{
    DownloadFile downloadFile = new DownloadFile();
    downloadFile.OnProgress += DownloadStatus;
    Console.WriteLine($"開始進行非同步檔案檔案下載");
    await downloadFile.Download();
    Console.WriteLine($"{Environment.NewLine}Press any key to Exist...");
    Console.ReadKey();
}

private static void DownloadStatus(object sender, DownloadFileEventArgs e)
{
    if (e.Percent % 10 == 0)
    {
        Console.Write($" {e.Percent}% ");
    }
    else
    {
        Console.Write($".");
    }
}
底下是執行結果
開始進行非同步檔案檔案下載
 0% ......... 10% ......... 20% ......... 30% ......... 40% ......... 50% ......... 60% ......... 70% ......... 80% ......... 90% ......... 100%
Press any key to Exist...

沒有留言:

張貼留言