WebClient.DownloadFile下载空文件主因是误用异步方法、未捕获异常、目录不存在、URL未编码;推荐改用HttpClient流式下载防OOM,并注意超时、重定向、认证及响应状态检查。

WebClient.DownloadFile 为什么下载完文件是空的?
常见现象是调用 WebClient.DownloadFile 后生成了文件,但大小为 0 字节,或打开报错“文件已损坏”。根本原因通常是未等待异步操作完成,或忽略了异常捕获。
- 同步下载必须用
DownloadFile(不是DownloadFileAsync),否则主线程不等就继续执行,可能在下载中途就结束了进程 - 网络错误(如 404、超时、重定向失败)会直接抛出异常,不处理就会静默失败;务必用
try/catch包住 - 目标路径的父目录不存在时,
DownloadFile不会自动创建,会抛出DirectoryNotFoundException - URL 中含空格或中文未编码,会导致
UriFormatException;用Uri.EscapeUriString预处理更稳妥
HttpClient 和 WebClient 到底该选哪个?
WebClient 简单但已标记为“过时”,.NET Core 5+ 中不再推荐;HttpClient 是现代首选,但默认不支持直接保存到文件,得自己流式写入。
-
WebClient:适合快速脚本、.NET Framework 项目;不支持超时精细控制,不能复用连接,高并发下性能差 -
HttpClient:需手动管理Stream和FileStream;支持设置Timeout、MaxResponseContentBufferSize,可复用实例提升性能 - 别每次请求都 new
HttpClient—— 容易引发SocketException(端口耗尽);应作为静态字段或用IHttpClientFactory - 示例关键行:
using var response = await client.GetAsync(url); using var stream = await response.Content.ReadAsStreamAsync();
下载大文件时内存暴涨甚至 OOM 怎么办?
用 DownloadFile 或 GetByteArrayAsync 会把整个响应体加载进内存,几 GB 的文件直接崩掉。必须走流式(streaming)路径。
- 绝对不要用
client.DownloadData或GetByteArrayAsync下载大文件 - 用
HttpClient+Stream.CopyToAsync,边读边写,内存占用恒定在几 KB - 记得设
client.Timeout = TimeSpan.FromMinutes(10),避免大文件卡住线程太久 - 临时文件建议先写到
.tmp后缀,下载成功再File.Move,防止程序中断留下残缺文件
如何处理重定向、认证和自定义 Header?
WebClient 默认跟随重定向,但无法干预;HttpClient 可控性更强,也更容易加 Token 或 User-Agent。
-
WebClient设置 Header:用webClient.Headers[HttpRequestHeader.UserAgent] = "MyApp/1.0" -
WebClient加 Bearer 认证:webClient.Headers[HttpRequestHeader.Authorization] = "Bearer abc123" -
HttpClient关闭自动重定向:new HttpClient(new HttpClientHandler { AllowAutoRedirect = false }),之后自己检查response.StatusCode == HttpStatusCode.Redirect - Cookie 处理:
HttpClientHandler构造时传入new CookieContainer()即可自动管理
response.IsSuccessStatusCode 就直接读流,结果 401 或 503 返回空内容还当成正常文件保存了。这事真发生过,而且很难 debug。










