WebClient 高層 HTTP 操作public class Form1 : Form
{
private WebClient client = new WebClient();
// ... 控制項聲明與 InitializeComponent 省略 ...
private void Start_Click(object sender, EventArgs e)
{
Thread th = new Thread(new ThreadStart(StartDownload));
th.Start();
}
private void StartDownload()
{
Start.Enabled = false; // 必須跨線程 Invoke,此處簡化
string URL = srcAddress.Text;
// 簡易解析檔名(實際應用建議用 Uri + Content-Disposition)
int n = URL.LastIndexOf("?");
string URLAddress = URL; // 若有查詢字串需移除
string fileName = URL.Substring(n + 1, URL.Length - n - 1);
string Dir = tarAddress.Text;
string Path = Dir + fileName;
try
{
// 預檢請求
WebRequest myre = WebRequest.Create(URLAddress);
}
catch (WebException exp)
{
MessageBox.Show(exp.Message, "Error");
return;
}
try
{
statusBar.Text = "開始下載檔案...";
// 方式一:WebClient 一鍵下載(推薦生產環境)
// client.DownloadFile(URLAddress, Path);
// 方式二:手動 Stream 處理(教學示範緩衝邏輯)
statusBar.Text = "正在接收資料...";
Stream str = client.OpenRead(URLAddress);
byte[] mbyte = new byte[100000]; // 100KB 緩衝
int allmybyte = mbyte.Length;
int startmbyte = 0;
while (allmybyte > 0)
{
int m = str.Read(mbyte, startmbyte, allmybyte);
if (m == 0) break;
startmbyte += m;
allmybyte -= m;
}
using (FileStream fstr = new FileStream(Path, FileMode.OpenOrCreate, FileAccess.Write))
fstr.Write(mbyte, 0, startmbyte);
str.Close();
statusBar.Text = "下載完畢!";
}
catch (WebException exp)
{
MessageBox.Show(exp.Message, "Error");
statusBar.Text = "";
}
finally
{
Start.Enabled = true; // 同樣需 Invoke
}
}
}
原代碼直接在工作線程訪問 Start.Enabled、statusBar.Text 會拋 InvalidOperationException。正確做法:
this.Invoke((Action)(() => Start.Enabled = false));
this.Invoke((Action)(() => statusBar.Text = "下載中..."));
Uri uri = new Uri(URLAddress);
string fileName = System.IO.Path.GetFileName(uri.LocalPath);
if (string.IsNullOrEmpty(fileName)) fileName = "download_" + DateTime.Now.Ticks;
client.DownloadProgressChanged += (s, e) =>
this.Invoke((Action)(() => progressBar.Value = e.ProgressPercentage));
client.DownloadFileCompleted += (s, e) =>
this.Invoke((Action)(() => statusBar.Text = e.Error?.Message ?? "完成"));
private async void Start_Click(object sender, EventArgs e)
{
Start.Enabled = false;
try
{
using (var http = new HttpClient())
using (var response = await http.GetAsync(URLAddress, HttpCompletionOption.ResponseHeadersRead))
using (var stream = await response.Content.ReadAsStreamAsync())
using (var fs = File.Create(Path))
{
var buffer = new byte[81920];
int read;
while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
await fs.WriteAsync(buffer, 0, read);
}
statusBar.Text = "下載完畢!";
}
catch (Exception ex) { statusBar.Text = ex.Message; }
finally { Start.Enabled = true; }
}
本文展示了從 WebClient 同步阻塞、手動 Stream 緩衝、背景執行緒 UI 分離,到現代 HttpClient + async/await 非阻塞下載的演進路徑。生產環境強烈建議採用 HttpClient 單例模式、支援斷點續傳、進度回報、取消令牌、重試策略,並妥善處理跨線程 UI 更新。