2009-04-27 14 views
8

我異步使用的WebRequest這樣從URL下載圖像:如何從網上下載一個圖像,顯示使用winforms在C#下載的進度?

public void Download(string url) 
{ 
    byte[] buffer = new byte[0x1000]; 
    WebRequest request = HttpWebRequest.Create(url); 
    request.Method = "GET"; 
    request.ContentType = "image/gif"; 

    request.BeginGetResponse(result => 
    { 
    WebRequest webRequest = result.AsyncState as WebRequest; 

    WebResponse response = webRequest.EndGetResponse(result); 
    ReadState readState = new ReadState() 
    { 
     Response = response.GetResponseStream(), 
     AccumulatedResponse = new MemoryStream(), 
     Buffer = buffer, 
    }; 

    readState.Response.BeginRead(buffer, 0, 
     readState.Buffer.Length, ReadCallback, readState); 
    }, request); 
} 

public void ReadCallback(IAsyncResult result) 
{ 
    ReadState readState = result.AsyncState as ReadState; 
    int bytesRead = readState.Response.EndRead(result); 
    if(bytesRead > 0) 
    { 
    readState.AccumulatedResponse.BeginWrite(readState.Buffer, 0, bytesRead, writeResult => 
    { 
     readState.AccumulatedResponse.EndWrite(writeResult); 
     readState.Response.BeginRead(readState.Buffer, 0, readState.Buffer.Length, ReadCallback, readState); 
    }, null); 
    } 
    else 
    { 
    readState.AccumulatedResponse.Flush(); 
    readState.Response.Close(); 
    pictureBox1.Image = Image.FromStream(readState.AccumulatedResponse); 
    } 
} 

public class ReadState 
{ 
    public Stream Response { get; set; } 
    public Stream AccumulatedResponse { get; set; } 
    public byte[] Buffer { get; set; } 
} 

和它的作品不錯,但我想顯示下載進度的瀏覽器做的,而不是隻顯示當它飾面。

如果我做

pictureBox1.Image = Image.FromStream(readState.AccumulatedResponse); 

它完成我得到一個例外,該圖片是無效的,即使它有一些數據之前。 無論如何顯示部分數據?

+1

如果圖像無效,就圖片框控件而言,您的運氣不大。就進度而言......檢查Response的ContentLength以瞭解文件的大小。 – 2009-04-27 07:59:09

回答

5

JPEG具有所謂的「漸進式JPEG」的特殊編碼模式,其中數據在逐漸升高的細節的多次通過壓縮。 Windows 7有built-in support這個。

+2

注意他在image/gif中被硬編碼,因此可能不會有幫助 – 2009-04-27 07:55:28

3

當你開始請求,檢查WebResponse.ContentLength財產,應該給你一個字節期待的總數。然後跟蹤ReadCallback方法中讀取的總字節數。其餘的應該是顯而易見的。 :)

[編輯]哎呀,我重讀的問題,這是你想要的並不完全符合。儘管如此,我仍然留下來,以防有人從中受益。

2

我不認爲你將管理使用.NET框架的內置方法,因爲它們會首先讀取完整的圖像,然後顯示它。您將需要找到其他支持顯示部分下載圖像的庫或自己編寫解析器。

4

我想顯示的 進展下載的瀏覽器去做,不會 只顯示當它完成。

你有兩個選擇:

  1. 使用WebClient.DownloadDataAsync。這將通過DownloadProgressChanged提高進度事件,並通過DownloadDataCompleted事件提供數據何時可用的最終通知。此時,您可以將圖像分配給PictureBox

  2. 如果您正在下載圖像以最終顯示在PictureBox控件中,那麼使用PictureBox.LoadAsync更容易。這也將通過其LoadProgressChanged事件和最終LoadCompleted提供進度更新完成。

4

你有PictureBox控件的問題,而不是部分下載。

的劈是使用WebBrowserControl,如IE能夠顯示部分圖像。

2

你也許可以做到這一點,但是,它需要的GIF文件結構的一些額外的知識。 Wotsit.org有幾個鏈接到gif結構文件,讓你開始。

一般的方法是獲取您的總累計數據,並從最後搜索,直到找到塊終止符的結尾。最後一個有效的數據塊和數據流結束之間的數據只是部分完成,並且必須被視爲垃圾數據。你想刪除它,並添加一個文件尾部塊的流。然後,您應該可以將此編輯的流加載到PictureBox中。

1

有一個事件可以用於異步Web下載請求,該請求會定期調用,並允許您直接更新ProgressBar控件。這裏有一個如何我用這個事件的例子:

delegate void SetProgressDelegate(int percentComplete); 
    /// <summary> 
    /// A thread-safe method for updating the file download progress bar. 
    /// </summary> 
    /// <param name="bytesReceived"></param> 
    /// <param name="totalBytes"></param> 
    void SetDownloadProgress(int percentComplete) 
    { 
     if (this.InvokeRequired) 
     { 
      SetProgressDelegate d = new SetProgressDelegate(SetDownloadProgress); 
      this.Invoke(d, new object[] { percentComplete }); 
     } 
     else 
     { 
      this.progressFileDownload.Value = percentComplete; 
     } 
    } 
    /// <summary> 
    /// Event handler to update the progress bar during file download. 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="e"></param> 
    void web_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 
    { 
     SetDownloadProgress(e.ProgressPercentage); 
    } 

這裏就是我如何連線了事件,並開始下載:

  WebClient web = new WebClient(); 
      web.DownloadFileCompleted += new AsyncCompletedEventHandler(web_DownloadFileCompleted); 
      web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(web_DownloadProgressChanged); 
      web.DownloadFileAsync(sourceUri, destinationFileName); 

解決方案中的文件直接讀取到內存中,而我的將其保存到磁盤上的文件中,所以此解決方案可能會或可能不適合您。如果顯示進度指示對您很重要,則此方法可以正常工作,您可以隨時下載到臨時文件,然後在完成後將該文件加載到映像控制中。

相關問題