2011-08-09 12 views
24

Thật khó để tìm thấy một ví dụ về mã tải xuống nhiều tệp bằng phương thức không đồng bộ của lớp webclient, nhưng mỗi lần tải xuống một tệp.Làm cách nào để tôi đồng bộ tải xuống nhiều tệp bằng cách sử dụng webclient, nhưng mỗi lần một tệp?

Tôi làm cách nào để bắt đầu tải xuống không đồng bộ, nhưng đợi cho đến khi lần đầu tiên được hoàn thành cho đến lần thứ hai, v.v ... Về cơ bản, một hàng đợi.

(lưu ý tôi không muốn sử dụng phương pháp đồng bộ, vì các chức năng tăng của phương pháp async.)

Mã dưới đây bắt đầu tất cả các tải của tôi cùng một lúc. (Thanh tiến trình là ở khắp mọi nơi)

private void downloadFile(string url) 
     { 
      WebClient client = new WebClient(); 

      client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged); 
      client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted); 

      // Starts the download 
      btnGetDownload.Text = "Downloading..."; 
      btnGetDownload.Enabled = false; 
      progressBar1.Visible = true; 
      lblFileName.Text = url; 
      lblFileName.Visible = true; 
      string FileName = url.Substring(url.LastIndexOf("/") + 1, 
          (url.Length - url.LastIndexOf("/") - 1)); 
      client.DownloadFileAsync(new Uri(url), "C:\\Test4\\" + FileName); 

     } 

     void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) 
     { 

     } 

     void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 
     { 
      double bytesIn = double.Parse(e.BytesReceived.ToString()); 
      double totalBytes = double.Parse(e.TotalBytesToReceive.ToString()); 
      double percentage = bytesIn/totalBytes * 100; 
      progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString()); 
     } 
+0

Bạn có thể quan tâm trong câu hỏi có liên quan này: [Kêu gọi một phương pháp không đồng bộ nối tiếp] (http://stackoverflow.com/questions/3909063/calling-an-asynchronous-method-serially) – Benjol

Trả lời

34

Điều tôi đã làm là điền Hàng đợi chứa tất cả các url của tôi, sau đó tôi tải xuống từng mục trong hàng đợi. Khi không có mục nào còn lại, tôi có thể xử lý tất cả các mục. Tôi đã nhạo báng một số mã dưới đây. Xin lưu ý, mã bên dưới là để tải xuống chuỗi chứ không phải tệp. Nó không nên quá khó khăn để sửa đổi mã dưới đây.

private Queue<string> _items = new Queue<string>(); 
    private List<string> _results = new List<string>(); 

    private void PopulateItemsQueue() 
    { 
     _items.Enqueue("some_url_here"); 
     _items.Enqueue("perhaps_another_here"); 
     _items.Enqueue("and_a_third_item_as_well"); 

     DownloadItem(); 
    } 

    private void DownloadItem() 
    { 
     if (_items.Any()) 
     { 
      var nextItem = _items.Dequeue(); 

      var webClient = new WebClient(); 
      webClient.DownloadStringCompleted += OnGetDownloadedStringCompleted; 
      webClient.DownloadStringAsync(new Uri(nextItem)); 
      return; 
     } 

     ProcessResults(_results); 
    } 

    private void OnGetDownloadedStringCompleted(object sender, DownloadStringCompletedEventArgs e) 
    { 
     if (e.Error == null && !string.IsNullOrEmpty(e.Result)) 
     { 
      // do something with e.Result string. 
      _results.Add(e.Result); 
     } 
     DownloadItem(); 
    } 

Edit: Tôi đã sửa đổi mã của bạn để sử dụng một Queue. Không hoàn toàn chắc chắn cách bạn muốn tiến độ làm việc. Tôi chắc chắn nếu bạn muốn tiến trình phục vụ cho tất cả các tải xuống, thì bạn có thể lưu trữ số mục trong phương thức 'PopulateItemsQueue()' và sử dụng trường đó trong phương thức thay đổi tiến trình.

private Queue<string> _downloadUrls = new Queue<string>(); 

    private void downloadFile(IEnumerable<string> urls) 
    { 
     foreach (var url in urls) 
     { 
      _downloadUrls.Enqueue(url); 
     } 

     // Starts the download 
     btnGetDownload.Text = "Downloading..."; 
     btnGetDownload.Enabled = false; 
     progressBar1.Visible = true; 
     lblFileName.Visible = true; 

     DownloadFile(); 
    } 

    private void DownloadFile() 
    { 
     if (_downloadUrls.Any()) 
     { 
      WebClient client = new WebClient(); 
      client.DownloadProgressChanged += client_DownloadProgressChanged; 
      client.DownloadFileCompleted += client_DownloadFileCompleted; 

      var url = _downloadUrls.Dequeue(); 
      string FileName = url.Substring(url.LastIndexOf("/") + 1, 
         (url.Length - url.LastIndexOf("/") - 1)); 

      client.DownloadFileAsync(new Uri(url), "C:\\Test4\\" + FileName); 
      lblFileName.Text = url; 
      return; 
     } 

     // End of the download 
     btnGetDownload.Text = "Download Complete"; 
    } 

    private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) 
    { 
     if (e.Error != null) 
     { 
      // handle error scenario 
      throw e.Error; 
     } 
     if (e.Cancelled) 
     { 
      // handle cancelled scenario 
     } 
     DownloadFile(); 
    } 

    void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 
    { 
     double bytesIn = double.Parse(e.BytesReceived.ToString()); 
     double totalBytes = double.Parse(e.TotalBytesToReceive.ToString()); 
     double percentage = bytesIn/totalBytes * 100; 
     progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString()); 
    } 
+0

Điều gì sẽ xảy ra nếu tải xuống không thành công (hoặc không hoàn thành vì bất kỳ lý do gì), sau đó phần còn lại của hàng đợi sẽ không được tải xuống dưới dạng client_DownloadFileCompleted sẽ không bao giờ kích hoạt đúng? Có cách nào để kiểm tra điều này, một chức năng thời gian chờ hoặc một cái gì đó? – Dan

+0

@Dan: Nếu xảy ra lỗi, nó có thể được phát hiện trong phương thức client_DownloadFileCompleted bằng cách kiểm tra thuộc tính Lỗi của tham số AsyncCompletedEventArgs. Tôi đã cập nhật mã để chứng minh nơi/làm thế nào điều này có thể được thực hiện. –

+0

'WebClient' là dùng một lần phải không? – Shimmy

1

tôi sẽ làm một phương pháp mới, ví dụ đặt tên getUrlFromQueue trả về cho tôi một url mới từ hàng đợi (bộ sưu tập hoặc mảng) và xóa nó .. sau đó nó gọi downloadFile (url) - và trong client_DownloadFileCompleted tôi gọi lại getUrlFromQueue.

2

Tôi đang cố gắng tìm hiểu vấn đề ở đâu. Nếu bạn chỉ gọi phương thức async cho tệp đầu tiên, nó sẽ không chỉ tải xuống tệp đó? Tại sao không sử dụng sự kiện client_downlaodFileCompleted để bắt đầu tải xuống tệp tiếp theo dựa trên một số giá trị được AsyncCompletedEvents truyền hoặc duy trì danh sách các tệp đã tải xuống dưới dạng biến tĩnh và có danh sách thứ tự lặp lại client_DownloadFileCompleted để tìm tệp tiếp theo cần tải xuống.

Hy vọng điều đó sẽ hữu ích nhưng vui lòng đăng thêm thông tin nếu tôi đã hiểu sai câu hỏi của bạn.

Các vấn đề liên quan