.net 使用WebClient或HttpClient下载文件?

kg7wmglp  于 2023-01-22  发布在  .NET
关注(0)|答案(9)|浏览(500)

我正在尝试从一个URL下载文件,我必须在WebClient和HttpClient之间做出选择。我参考了this文章和互联网上的其他几篇文章。到处都有人建议使用HttpClient,因为它具有强大的异步支持和其他.Net 4.5特权。但我仍然不完全相信,需要更多的投入。
我正在使用下面的代码从互联网上下载文件:

Web客户端:

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

HTTP客户端:

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

从我的Angular 来看,我只能看到使用WebClient的一个缺点,那就是非异步调用阻塞了调用线程。但是如果我不担心线程阻塞,或者使用client.DownloadFileAsync()来利用异步支持呢?
另一方面,如果我使用HttpClient,我不是将文件的每一个字节都加载到内存中,然后将其写入本地文件吗?如果文件太大,内存开销不是很大吗?如果我们使用WebClient,这可以避免,因为它将直接写入本地文件,而不消耗系统内存。
所以,如果性能是我的绝对优先事项,我应该使用哪种方法下载?我想澄清一下,如果我上面的假设是错误的,我也愿意使用其他方法。

8ftvxx2r

8ftvxx2r1#

你可以用.Net 4. 5+原生地做。我试着用你的方式做,然后我刚刚在Intellisense中找到了一个似乎有意义的方法。
https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.copytoasync?view=netframework-4.7.2

uri = new Uri(generatePdfsRetrieveUrl + pdfGuid + ".pdf");
HttpClient client = new HttpClient();
var response = await client.GetAsync(uri);
using (var fs = new FileStream(
    HostingEnvironment.MapPath(string.Format("~/Downloads/{0}.pdf", pdfGuid)), 
    FileMode.CreateNew))
{
    await response.Content.CopyToAsync(fs);
}
sr4lhrrt

sr4lhrrt2#

这是我的方法。
如果您正在调用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();
            }
    }
}
klr1opcd

klr1opcd3#

为了在使用WebClient的现有代码中使用HttpClient,我编写了一个小的扩展方法,以在代码中使用DownloadFileTaskAsync的相同方式使用它。

using (var client = new System.Net.Http.HttpClient()) // WebClient
{
    var fileName = @"C:\temp\imgd.jpg";
    var uri = new Uri("https://yourwebsite.com/assets/banners/Default.jpg");

    await client.DownloadFileTaskAsync(uri, fileName);
}

要使用它,我们可以有这样的扩展方法:

public static class HttpClientUtils
{
    public static async Task DownloadFileTaskAsync(this HttpClient client, Uri uri, string FileName)
    {
        using (var s = await client.GetStreamAsync(uri))
        {
            using (var fs = new FileStream(FileName, FileMode.CreateNew))
            {
                await s.CopyToAsync(fs);
            }
        }
    }
}
3gtaxfhh

3gtaxfhh4#

对于重复调用的代码,您希望将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;
        }
    }
}
sbdsn5lh

sbdsn5lh5#

Here’s one way to use it to download a URL and save it to a file:(我使用的是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下载和保存文件的信息。

ss2ws0br

ss2ws0br6#

如果您希望(或必须)同步执行此操作,但使用的是漂亮的HttpClient类,那么有一种简单的方法:

string requestString = @"https://example.com/path/file.pdf";

var GetTask = httpClient.GetAsync(requestString);
GetTask.Wait(WebCommsTimeout); // WebCommsTimeout is in milliseconds

if (!GetTask.Result.IsSuccessStatusCode)
{
    // write an error
    return;
}
                    
using (var fs = new FileStream(@"c:\path\file.pdf", FileMode.CreateNew))
{
    var ResponseTask = GetTask.Result.Content.CopyToAsync(fs);
    ResponseTask.Wait(WebCommsTimeout);
}
e1xvtsh3

e1xvtsh37#

我的方法很简单。使用FileStream你可以将它存储在本地文件夹中,或者使用FileStreamResult从API返回它。存储到本地文件夹的示例:

private async Task SaveDataIntoLocalFolder(string url,string fileName)
{
    using (var client = new HttpClient())
    {
        var response = await client.GetAsync(url);
        if (response.IsSuccessStatusCode)
        {
           var stream = await response.Content.ReadAsStreamAsync();
           var fileInfo = new FileInfo(fileName);
           using (var fileStream = fileInfo.OpenWrite())
           {
              await stream.CopyToAsync(fileStream);
           }
        }
        else
        {
          throw new Exception("File not found");
        }
    }     
}
eblbsuwk

eblbsuwk8#

这是一个简单的UWP演示程序,用于下载图像文件。只需粘贴图像URL链接并按下载按钮。您可以识别文件类型并更改fileName以下载所需的文件。

主页.xaml

<Page
    x:Class="HttpDownloader.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpDownloader"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <StackPanel>
            <TextBox x:Name="uriInput"
                     Header="URI:" PlaceholderText="Please provide an uri"
                     Width="300"
                     HorizontalAlignment="Center"/>
            <Button Content="Dowload"
                    HorizontalAlignment="Center"
                    Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Page>

主页.xaml.xs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net.Http;
using System.Net;
using Windows.Storage.Streams;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Graphics.Imaging;
using System.Threading;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace HttpDownloader
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            HttpClient client = new HttpClient();
            string imageUrl = uriInput.Text;
            try
            {
                using (var cancellationTokenSource = new CancellationTokenSource(50000))
                {
                    var uri = new Uri(WebUtility.HtmlDecode(imageUrl));
                    using (var response = await client.GetAsync(uri, cancellationTokenSource.Token))
                    {
                        response.EnsureSuccessStatusCode();
                        var mediaType = response.Content.Headers.ContentType.MediaType;
                        string fileName = DateTime.Now.ToString("yyyyMMddhhmmss");
                        if (mediaType.IndexOf("jpg", StringComparison.OrdinalIgnoreCase) >= 0
                            || mediaType.IndexOf("jpeg", StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            fileName += ".jpg";
                        }
                        else if (mediaType.IndexOf("png", StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            fileName += ".png";
                        }
                        else if (mediaType.IndexOf("gif", StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            fileName += ".gif";
                        }
                        else if (mediaType.IndexOf("bmp", StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            fileName += ".bmp";
                        }
                        else
                        {
                            fileName += ".png";
                        }

                        // Get the app's local folder.
                        StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;

                        // Create a new subfolder in the current folder.
                        // Replace the folder if already exists.
                        string desiredName = "Images";
                        StorageFolder newFolder = await localFolder.CreateFolderAsync(desiredName, CreationCollisionOption.ReplaceExisting);
                        StorageFile newFile = await newFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

                        using (Stream streamStream = await response.Content.ReadAsStreamAsync())
                        {
                            using (Stream streamToWriteTo = File.Open(newFile.Path, FileMode.Create))
                            {
                                await streamStream.CopyToAsync(streamToWriteTo);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception occur");
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

您将在此文件夹中找到图像。
Users/[current user name]/AppData/Local/Packages/[Application package name]/LocalState/Images

6xfqseft

6xfqseft9#

HttpClient _client=new HttpClient();
   byte[] buffer = null;
   try
   {       
      HttpResponseMessage task = await _client.GetAsync("https://**FILE_URL**");
      Stream task2 = await task.Content.ReadAsStreamAsync();
      using (MemoryStream ms = new MemoryStream())
      {
        await task2.CopyToAsync(ms);
        buffer = ms.ToArray();
      }
      File.WriteAllBytes("C:/**PATH_TO_SAVE**", buffer);  
   }
   catch
   {

   }

相关问题