首页 文章

使用WebClient或HttpClient下载文件?

提问于
浏览
8

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

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

WebClient:

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可以避免这种情况,因为它将直接写入本地文件而不会消耗系统内存 .

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

3 回答

  • 1

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

    public static class WebUtils
    {
        private static Lazy<IWebProxy> proxy = new Lazy<IWebProxy>(() => 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下载和保存文件的所有信息 .

    根据以下this链接:

  • 0

    对于重复调用的代码, do not 要将 HttpClient 放入 using 块(it will leave hanging ports open

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

    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;
            }
        }
    }
    
  • 1

    这是我的方法 .

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

    public async Task<ActionResult> 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();
                }
        }
    }
    

相关问题