使用WebClient或HttpClient下载文件?

我试图从URL下载文件,我必须在WebClient和HttpClient之间进行选择。 我在互联网上引用了这篇文章和其他几篇文章。 无处不在,由于其强大的异步支持和其他.Net 4.5权限,建议使用HttpClient。 但我仍然不完全相信并需要更多的投入。

我使用下面的代码从互联网上下载文件:

Web客户端:

WebClient client = new WebClient(); client.DownloadFile(downloadUrl, filePath); 

HttpClient的:

 using (HttpClient client = new HttpClient()) { using (HttpResponseMessage response = await client.GetAsync(url)) using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync()) { } } 

从我的角度来看,我只能看到使用WebClient的一个缺点,那就是非异步调用,阻塞调用线程。 但是,如果我不担心阻塞线程或使用client.DownloadFileAsync()来利用异步支持,该怎么办?

另一方面,如果我使用HttpClient,是不是我将文件的每个字节加载到内存中然后将其写入本地文件? 如果文件太大,内存开销不会很贵吗? 如果我们使用WebClient可以避免这种情况,因为它将直接写入本地文件而不会消耗系统内存。

那么,如果性能是我的首要任务,我应该使用哪种方法进行下载? 如果我的上述假设是错误的,我想澄清一下,我也愿意接受替代方法。

这是我的方法。

如果您正在调用WebApi来获取文件,那么从控制器方法可以使用HttpClient GET请求并使用FileStreamResult返回类型返回文件流。

 public async Task GetAttachment(int FileID) { UriBuilder uriBuilder = new UriBuilder(); uriBuilder.Scheme = "https"; uriBuilder.Host = "api.example.com"; var Path = "/files/download"; uriBuilder.Path = Path; using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri(uriBuilder.ToString()); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Add("authorization", access_token); //if any client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync(uriBuilder.ToString()); if (response.IsSuccessStatusCode) { System.Net.Http.HttpContent content = response.Content; var contentStream = await content.ReadAsStreamAsync(); // get the actual content stream return File(contentStream, content_type, filename); } else { throw new FileNotFoundException(); } } } 

这是使用它下载URL并将其保存到文件的一种方法:(我使用的是Windows 7,因此我没有使用WindowsRT,所以我也使用System.IO。)

 public static class WebUtils { private static Lazy proxy = new Lazy(() => string.IsNullOrEmpty(Settings.Default.WebProxyAddress) ? null : new WebProxy { Address = new Uri(Settings.Default.WebProxyAddress), UseDefaultCredentials = true }); public static IWebProxy Proxy { get { return WebUtils.proxy.Value; } } public static Task DownloadAsync(string requestUri, string filename) { if (requestUri == null) throw new ArgumentNullException(“requestUri”); return DownloadAsync(new Uri(requestUri), filename); } public static async Task DownloadAsync(Uri requestUri, string filename) { if (filename == null) throw new ArgumentNullException(“filename”); if (Proxy != null) WebRequest.DefaultWebProxy = Proxy; using (var httpClient = new HttpClient()) { using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) { using (Stream contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync(), stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.LargeBufferSize, true)) { await contentStream.CopyToAsync(stream); } } } } } 

请注意,代码正在保存我在设置中使用的代理服务器的地址(在工作中),如果指定了此类设置,则使用该地址。 否则,它应告诉您有关使用HttpClient beta下载和保存文件的所有信息。

按照以下链接:

对于重复调用的代码,您希望将HttpClient放入using块中( 它会使挂起的端口保持打开状态 )

为了使用HttpClient下载文件,我发现这个扩展方法对我来说似乎是一个好的和可靠的解决方案:

 public static class HttpContentExtensions { public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite) { string pathname = Path.GetFullPath(filename); if (!overwrite && File.Exists(filename)) { throw new InvalidOperationException(string.Format("File {0} already exists.", pathname)); } FileStream fileStream = null; try { fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None); return content.CopyToAsync(fileStream).ContinueWith( (copyTask) => { fileStream.Close(); }); } catch { if (fileStream != null) { fileStream.Close(); } throw; } } }