如何从 C# 中的 URL 下载文件?

Posted

技术标签:

【中文标题】如何从 C# 中的 URL 下载文件?【英文标题】:How to download a file from a URL in C#? 【发布时间】:2010-09-23 09:20:17 【问题描述】:

从 URL 路径下载文件的简单方法是什么?

【问题讨论】:

看看 System.Net.WebClient 【参考方案1】:
using (var client = new WebClient())

    client.DownloadFile("http://example.com/file/song/a.mpeg", "a.mpeg");

【讨论】:

有史以来最好的解决方案,但我想添加 1 条重要的行 'client.Credentials = new NetworkCredential("UserName", "Password");' 一个受欢迎的副作用:此方法还支持本地文件作为第一个参数 虽然我认为 WebClient 似乎是一个更直接和简单的解决方案。 @copa017:或者一个危险的,例如,如果 URL 是用户提供的并且 C# 代码在 Web 服务器上运行。 WebRequest、WebClient 和 ServicePoint 在 .Net 6 链接中已过时 --> docs.microsoft.com/en-us/dotnet/core/compatibility/networking/…【参考方案2】:

包括这个命名空间

using System.Net;

异步下载并放置一个ProgressBar以在UI线程本身内显示下载状态

private void BtnDownload_Click(object sender, RoutedEventArgs e)

    using (WebClient wc = new WebClient())
    
        wc.DownloadProgressChanged += wc_DownloadProgressChanged;
        wc.DownloadFileAsync (
            // Param1 = Link of file
            new System.Uri("http://www.sayka.com/downloads/front_view.jpg"),
            // Param2 = Path to save
            "D:\\Images\\front_view.jpg"
        );
    

// Event to track the progress
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)

    progressBar.Value = e.ProgressPercentage;

【讨论】:

问题要求最简单的方法。让事情变得更复杂并不是让事情变得最简单。 大多数人在下载时更喜欢进度条。所以我只是写了最简单的方法来做到这一点。这可能不是答案,但它符合 *** 的要求。那就是帮助别人。 如果您忽略进度条,这与其他答案一样简单。此答案还包括命名空间并使用异步进行 I/O。此外,问题并不要求最简单的方法,只是一种简单的方法。 :) @Jessedegans 已经有一个答案显示了如何在没有进度条的情况下简单地下载。这就是为什么我写了一个有助于异步下载和进度条实现的答案 这个答案很好,可能比支持更多的答案更好,更详细。下载文件时需要一个进度指示器几乎是显而易见的。异步功能是一个好处。我一直在寻找这样的实现。【参考方案3】:

使用System.Net.WebClient.DownloadFile:

string remoteUri = "http://www.contoso.com/library/homepage/images/";
string fileName = "ms-banner.gif", myStringWebResource = null;

// Create a new WebClient instance.
using (WebClient myWebClient = new WebClient())

    myStringWebResource = remoteUri + fileName;
    // Download the Web resource and save it into the current filesystem folder.
    myWebClient.DownloadFile(myStringWebResource, fileName);        

【讨论】:

WebClient 已过时,请参阅github.com/dotnet/runtime/issues/33125【参考方案4】:
using System.Net;

WebClient webClient = new WebClient();
webClient.DownloadFile("http://mysite.com/myfile.txt", @"c:\myfile.txt");

【讨论】:

欢迎来到 SO!通常,对于已经获得高度评价的现有问题和旧问题发布低质量答案并不是一个好主意。 我从 seanb 的评论中找到了我的答案,但我确实更喜欢这个“低质量”的答案。它完整​​(使用语句),简洁易懂。作为一个老问题是无关紧要的,恕我直言。 但它认为使用 Using 的答案要好得多,因为我认为 WebClient 应该在使用后丢弃。将其放入 using 可确保将其处理掉。 此代码示例中与dispose无关...这里的using语句只是显示要使用的命名空间,不是WebClient用于使用为dispose...【参考方案5】:

在向控制台打印状态时下载文件的完整类。

using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Threading;

class FileDownloader

    private readonly string _url;
    private readonly string _fullPathWhereToSave;
    private bool _result = false;
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0);

    public FileDownloader(string url, string fullPathWhereToSave)
    
        if (string.IsNullOrEmpty(url)) throw new ArgumentNullException("url");
        if (string.IsNullOrEmpty(fullPathWhereToSave)) throw new ArgumentNullException("fullPathWhereToSave");

        this._url = url;
        this._fullPathWhereToSave = fullPathWhereToSave;
    

    public bool StartDownload(int timeout)
    
        try
        
            System.IO.Directory.CreateDirectory(Path.GetDirectoryName(_fullPathWhereToSave));

            if (File.Exists(_fullPathWhereToSave))
            
                File.Delete(_fullPathWhereToSave);
            
            using (WebClient client = new WebClient())
            
                var ur = new Uri(_url);
                // client.Credentials = new NetworkCredential("username", "password");
                client.DownloadProgressChanged += WebClientDownloadProgressChanged;
                client.DownloadFileCompleted += WebClientDownloadCompleted;
                Console.WriteLine(@"Downloading file:");
                client.DownloadFileAsync(ur, _fullPathWhereToSave);
                _semaphore.Wait(timeout);
                return _result && File.Exists(_fullPathWhereToSave);
            
        
        catch (Exception e)
        
            Console.WriteLine("Was not able to download file!");
            Console.Write(e);
            return false;
        
        finally
        
            this._semaphore.Dispose();
        
    

    private void WebClientDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    
        Console.Write("\r     -->    0%.", e.ProgressPercentage);
    

    private void WebClientDownloadCompleted(object sender, AsyncCompletedEventArgs args)
    
        _result = !args.Cancelled;
        if (!_result)
        
            Console.Write(args.Error.ToString());
        
        Console.WriteLine(Environment.NewLine + "Download finished!");
        _semaphore.Release();
    

    public static bool DownloadFile(string url, string fullPathWhereToSave, int timeoutInMilliSec)
    
        return new FileDownloader(url, fullPathWhereToSave).StartDownload(timeoutInMilliSec);
    

用法:

static void Main(string[] args)

    var success = FileDownloader.DownloadFile(fileUrl, fullPathWhereToSave, timeoutInMilliSec);
    Console.WriteLine("Done  - success: " + success);
    Console.ReadLine();

【讨论】:

请您解释一下为什么在这种情况下使用SemaphoreSlim【参考方案6】:

试试这个:

private void downloadFile(string url)

     string file = System.IO.Path.GetFileName(url);
     WebClient cln = new WebClient();
     cln.DownloadFile(url, file);

【讨论】:

文件将保存在哪里? 文件将保存在可执行文件所在的位置。如果您想要完整路径,请使用完整路径和文件(这是要下载的项目的文件名)【参考方案7】:

您也可以在 WebClient 类中使用 DownloadFileAsync 方法。它将具有指定 URI 的资源下载到本地文件。此方法也不会阻塞调用线程。

示例:

    webClient.DownloadFileAsync(new Uri("http://www.example.com/file/test.jpg"), "test.jpg");

更多信息:

http://csharpexamples.com/download-files-synchronous-asynchronous-url-c/

【讨论】:

【参考方案8】:

使用GetIsNetworkAvailable() 检查网络连接,以避免在未连接到网络时创建空文件。

if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())

    using (System.Net.WebClient client = new System.Net.WebClient())
                            
          client.DownloadFileAsync(new Uri("http://www.examplesite.com/test.txt"),
          "D:\\test.txt");
                      

【讨论】:

我建议不要使用GetIsNetworkAvailable(),因为根据我的经验,会返回太多误报。 除非您在局域网等计算机网络中,否则GetIsNetworkAvailable() 将始终正确返回。在这种情况下,您可以使用System.Net.WebClient().OpenRead(Uri) 方法来查看它是否在给定默认 url 时返回。见WebClient.OpenRead()【参考方案9】:

以下代码包含使用原始名称下载文件的逻辑

private string DownloadFile(string url)
    

        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
        string filename = "";
        string destinationpath = Environment;
        if (!Directory.Exists(destinationpath))
        
            Directory.CreateDirectory(destinationpath);
        
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponseAsync().Result)
        
            string path = response.Headers["Content-Disposition"];
            if (string.IsNullOrWhiteSpace(path))
            
                var uri = new Uri(url);
                filename = Path.GetFileName(uri.LocalPath);
            
            else
            
                ContentDisposition contentDisposition = new ContentDisposition(path);
                filename = contentDisposition.FileName;

            

            var responseStream = response.GetResponseStream();
            using (var fileStream = File.Create(System.IO.Path.Combine(destinationpath, filename)))
            
                responseStream.CopyTo(fileStream);
            
        

        return Path.Combine(destinationpath, filename);
    

【讨论】:

在我尝试此代码的情况下,路径为空,文件名也为空,不知道该怎么办【参考方案10】:

根据我的研究,我发现WebClient.DownloadFileAsync 是下载文件的最佳方式。它在 System.Net 命名空间中可用,它也支持 .net 核心。

这里是下载文件的示例代码。

using System;
using System.IO;
using System.Net;
using System.ComponentModel;

public class Program

    public static void Main()
    
        new Program().Download("ftp://localhost/test.zip");
    
    public void Download(string remoteUri)
    
        string FilePath = Directory.GetCurrentDirectory() + "/tepdownload/" + Path.GetFileName(remoteUri); // path where download file to be saved, with filename, here I have taken file name from supplied remote url
        using (WebClient client = new WebClient())
        
            try
            
                if (!Directory.Exists("tepdownload"))
                
                    Directory.CreateDirectory("tepdownload");
                
                Uri uri = new Uri(remoteUri);
                //password username of your file server eg. ftp username and password
                client.Credentials = new NetworkCredential("username", "password");
                //delegate method, which will be called after file download has been complete.
                client.DownloadFileCompleted += new AsyncCompletedEventHandler(Extract);
                //delegate method for progress notification handler.
                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgessChanged);
                // uri is the remote url where filed needs to be downloaded, and FilePath is the location where file to be saved
                client.DownloadFileAsync(uri, FilePath);
            
            catch (Exception)
            
                throw;
            
        
    
    public void Extract(object sender, AsyncCompletedEventArgs e)
    
        Console.WriteLine("File has been downloaded.");
    
    public void ProgessChanged(object sender, DownloadProgressChangedEventArgs e)
    
        Console.WriteLine($"Download status: e.ProgressPercentage%.");
    

上面的代码文件将被下载到项目目录的tepdownload文件夹中。请阅读代码中的注释以了解上述代码的作用。

【讨论】:

【参考方案11】:

WebClient 已过时

如果您想下载到文件,请避免先使用ResponseHeadersRead 读取内存,如下所示:

static public async Task HttpDownloadFileAsync(HttpClient httpClient, string url, string fileToWriteTo) 
  using HttpResponseMessage response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
  using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync(); 
  using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create); 
  await streamToReadFrom.CopyToAsync(streamToWriteTo);

上面的代码更像是一个大纲,添加正确的错误/异常处理不是微不足道的,进度报告也不是微不足道的,处置也是如此。

我为DownoadFileAsyncGetToStringAsyncPostToStringAsync 提出了一组C# 9.0 扩展类

namespace System.Net.Http 

  // HttpResponse is in one of 3 states:
  // - ResponseMessageInfo is object && ResponseMessageInfo.IsSuccessStatusCode -> success, inspect ResponseMessageInfo for StatusCode etc
  // - ResponseMessageInfo is object && !ResponseMessageInfo.IsSuccessStatusCode -> failure, inspect ResponseMessageInfo for StatusCode, ReasonPhrase etc
  // - ResponseMessageInfo is null -> exception, inspect ExceptionInfo fields
  public record HttpResponse 

    // copies of HttpRequestMessage and HttpResponseMessage which do not have the content and do not need to be disposed
    public record HttpRequestMessageInfo(HttpRequestHeaders Headers, HttpMethod Method, HttpRequestOptions Options, Uri? RequestUri, Version Version, HttpVersionPolicy VersionPolicy);
    public record HttpResponseMessageInfo(HttpResponseHeaders Headers, bool IsSuccessStatusCode, string? ReasonPhrase, HttpRequestMessageInfo RequestMessage, HttpStatusCode StatusCode, HttpResponseHeaders TrailingHeaders, Version Version);

    // holds Http exception information
    public record HttpExceptionInfo(HttpRequestMessageInfo HttpRequestMessage, string ErrorMessage, WebExceptionStatus? WebExceptionStatus);

    // if ResponseMessageInfo is null ExceptionInfo is not and vice versa
    public HttpResponseMessageInfo? ResponseMessageInfo  get; init; 
    public HttpExceptionInfo? ExceptionInfo  get; init; 

    public HttpResponse(HttpRequestMessage requestMessage, HttpResponseMessage responseMessage) 
      var requestMessageInfo = new HttpRequestMessageInfo(requestMessage.Headers, requestMessage.Method, requestMessage.Options, requestMessage.RequestUri, requestMessage.Version, requestMessage.VersionPolicy);
      ResponseMessageInfo = new(responseMessage.Headers, responseMessage.IsSuccessStatusCode, responseMessage.ReasonPhrase, requestMessageInfo, responseMessage.StatusCode, responseMessage.TrailingHeaders, responseMessage.Version);
      ExceptionInfo = null;
    

    public HttpResponse(HttpRequestMessage requestMessage, Exception exception) 
      ResponseMessageInfo = null;
      var requestMessageInfo = new HttpRequestMessageInfo(requestMessage.Headers, requestMessage.Method, requestMessage.Options, requestMessage.RequestUri, requestMessage.Version, requestMessage.VersionPolicy);

      if (exception is WebException ex1 && ex1.Status == WebExceptionStatus.ProtocolError) 
        using HttpWebResponse? httpResponse = (HttpWebResponse?)ex1.Response;
        ExceptionInfo = new(requestMessageInfo, httpResponse?.StatusDescription ?? "", ex1.Status);
       
      else if (exception is WebException ex2) ExceptionInfo = new(requestMessageInfo, ex2.FullMessage(), ex2.Status);
      else if (exception is TaskCanceledException ex3 && ex3.InnerException is TimeoutException) ExceptionInfo = new(requestMessageInfo, ex3.InnerException.FullMessage(), WebExceptionStatus.Timeout);
      else if (exception is TaskCanceledException ex4) ExceptionInfo = new(requestMessageInfo, ex4.FullMessage(), WebExceptionStatus.RequestCanceled);
      else ExceptionInfo = new(requestMessageInfo, exception.FullMessage(), null);
    

    public override string ToString() 
      if (ResponseMessageInfo is object) 
        var msg = ResponseMessageInfo.IsSuccessStatusCode ? "Success" : "Failure";
        msg += $" Enum.GetName(typeof(HttpStatusCode), ResponseMessageInfo.StatusCode)";
        if (ResponseMessageInfo.ReasonPhrase is object) msg += $" ResponseMessageInfo.ReasonPhrase";
        return msg;

       else if (ExceptionInfo is object) 
        var msg = "Failure";
        msg += $" ExceptionInfo.ErrorMessage";
        if (ExceptionInfo.WebExceptionStatus is object) msg += $" Enum.GetName(typeof(WebExceptionStatus), ExceptionInfo.WebExceptionStatus)";
        return msg;
      
      return "NA"; // never reach here
    
  


  public static class ExtensionMethods 

    // progressCallback recieves (bytesRecieved, percent, speedKbSec) and can return false to cancell download
    public static async Task<(bool success, HttpResponse httpResponse)> DownloadFileAsync(this HttpClient httpClient, Uri requestUri, string fileToWriteTo, CancellationTokenSource? cts = null, Func<long, int, float, bool>? progressCallback = null) 
      var httpRequestMessage = new HttpRequestMessage  Method = HttpMethod.Get, RequestUri = requestUri ;
      var created = false;

      try 
        var cancellationToken = cts?.Token ?? default;

        using HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
        if (!httpResponseMessage.IsSuccessStatusCode) return (false, new(httpRequestMessage, httpResponseMessage));
        var contentLength = httpResponseMessage.Content.Headers.ContentLength;

        using Stream streamToReadFrom = await httpResponseMessage.Content.ReadAsStreamAsync();
        using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create);
        created = true;

        var buffer = new byte[81920]; 
        var bytesRecieved = (long)0;
        var stopwatch = Stopwatch.StartNew();
        int bytesInBuffer;
        while ((bytesInBuffer = await streamToReadFrom.ReadAsync(buffer, cancellationToken)) != 0) 
          await streamToWriteTo.WriteAsync(buffer.AsMemory(0, bytesInBuffer), cancellationToken);
          bytesRecieved += bytesInBuffer;
          if (progressCallback is object) 
            var percent = contentLength is object && contentLength != 0 ? (int)Math.Floor(bytesRecieved / (float)contentLength * 100.0) : 0;
            var speedKbSec = (float)((bytesRecieved / 1024.0) / (stopwatch.ElapsedMilliseconds / 1000.0));
            var proceed = progressCallback(bytesRecieved, percent, speedKbSec);
            if (!proceed) 
              httpResponseMessage.ReasonPhrase = "Callback cancelled download";
              httpResponseMessage.StatusCode = HttpStatusCode.PartialContent;
              return (false, new(httpRequestMessage, httpResponseMessage));
            
          
        

        return (true, new(httpRequestMessage, httpResponseMessage));
      
      catch (Exception ex) 
        if (created) try  File.Delete(fileToWriteTo);  catch  ;
        return (false, new(httpRequestMessage, ex));
      
    

    public static async Task<(string? ResponseAsString, HttpResponse httpResponse)> GetToStringAsync(this HttpClient httpClient, Uri requestUri, CancellationTokenSource? cts = null) 
      var httpRequestMessage = new HttpRequestMessage  Method = HttpMethod.Get, RequestUri = requestUri ;
      try 
        var cancellationToken = cts?.Token ?? default;
        using var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, cancellationToken);
        if (!httpResponseMessage.IsSuccessStatusCode) return (null, new(httpRequestMessage, httpResponseMessage));
        
        var responseAsString = await httpResponseMessage.Content.ReadAsStringAsync();
        return (responseAsString, new(httpRequestMessage, httpResponseMessage));
      
      catch (Exception ex) 
        return (null, new(httpRequestMessage, ex)); ;
      
    

    public static async Task<(string? ResponseAsString, HttpResponse httpResponse)> PostToStringAsync(this HttpClient httpClient, Uri requestUri, HttpContent postBuffer, CancellationTokenSource? cts = null) 
      var httpRequestMessage = new HttpRequestMessage  Method = HttpMethod.Post, RequestUri = requestUri, Content = postBuffer ;
      try 
        var cancellationToken = cts?.Token ?? default;
        using var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, cancellationToken);
        if (!httpResponseMessage.IsSuccessStatusCode) return (null, new(httpRequestMessage, httpResponseMessage));

        var responseAsString = await httpResponseMessage.Content.ReadAsStringAsync();
        return (responseAsString, new(httpRequestMessage, httpResponseMessage));
      
      catch (Exception ex) 
        return (null, new(httpRequestMessage, ex));
      
    

  


namespace System 
  public static class ExtensionMethods 
    public static string FullMessage(this Exception ex) 
      if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"total[next.FullMessage()] ") + "]";
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      var innerMsg = ex.InnerException?.FullMessage();
      if (innerMsg is object && innerMsg!=msg) msg = $"msg [ innerMsg ]";
      return msg;
    
  

使用方法:

// download to file
var lastPercent = 0;
bool progressCallback(long bytesRecieved, int percent, float speedKbSec) 
  if (percent > lastPercent) 
    lastPercent = percent;
    Log($"Downloading... percent% speedKbSec/1024.0:0.00Mbps");
  
  return true;


var (success, httpResponse) = await httpClient.DownloadFileAsync(
  new(myUrlString), 
  localFileName, 
  null, // CancellationTokenSource 
  progressCallback
);

if (success) 
  // file downloaded to localFile, httpResponse.ResponseMessageInfo contain 
  // extra information ie headers and status code

 else 
  Log(httpResponse.ToString()); // human friendly error information
  // if httpResponse.ResponseMessageInfo is object then server refused the request - 
  // examine httpResponse.ResponseMessageInfo.HttpStatusCode etc
  // else we had a Http exception - examine httpResponse.ExceptionInfo 



// Http get
var (responseAsString, httpResponse) = await httpClient.GetToStringAsync(url);
if (responseAsString is object) 
  // responseAsString contains the string response from the server

 else 
  // as for DownloadFileAsync



// http post
var postBuffer = new StringContent(jsonInString, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
var (responseAsString, httpResponse) = await httpClient.PostToStringAsync(url, postBuffer);

if (responseAsString is object) 
  // responseAsString contains the string response from the server

 else 
  Log(httpResponse.ToString()); // human friendly error informaiton
  // as for DownloadFileAsync

【讨论】:

【参考方案12】:

您可能需要在文件下载期间了解状态并更新 ProgressBar,或在发出请求之前使用凭据。

这是一个涵盖这些选项的示例。 Lambda 表示法字符串插值已被使用:

using System.Net;
// ...

using (WebClient client = new WebClient()) 
    Uri ur = new Uri("http://remotehost.do/images/img.jpg");

    //client.Credentials = new NetworkCredential("username", "password");
    String credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes("Username" + ":" + "MyNewPassword"));
    client.Headers[HttpRequestHeader.Authorization] = $"Basic credentials";

    client.DownloadProgressChanged += (o, e) =>
    
        Console.WriteLine($"Download status: e.ProgressPercentage%.");

        // updating the UI
        Dispatcher.Invoke(() => 
            progressBar.Value = e.ProgressPercentage;
        );
    ;

    client.DownloadDataCompleted += (o, e) => 
    
        Console.WriteLine("Download finished!");
    ;

    client.DownloadFileAsync(ur, @"C:\path\newImage.jpg");

【讨论】:

一些关于你的代码语句目的的cmet会有所帮助,对于那些不熟悉异步操作和跨线程调用的人。【参考方案13】:

如果您需要设置 HeadersCookies 来下载文件,您需要做的事情稍有不同。这是一个示例...

// Pass in the HTTPGET URL, Full Path w/Filename, and a populated Cookie Container (optional)
private async Task DownloadFileRequiringHeadersAndCookies(string getUrl, string fullPath, CookieContainer cookieContainer, CancellationToken cancellationToken)

    cookieContainer ??= new CookieContainer();  // TODO: FILL ME AND PASS ME IN

    using (var handler = new HttpClientHandler()
    
        UseCookies = true,
        CookieContainer = cookieContainer, // This will, both, use the cookies passed in, and update/create cookies from the response
        ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true, // use only if it gets angry about the SSL endpoints
        AllowAutoRedirect = true,
    )
    
        using (var client = new HttpClient(handler))
        
            SetHeaders(client);

            using (var response = await client.GetAsync(getUrl, cancellationToken))
            
                if (response.IsSuccessStatusCode)
                
                    var bytes = await response.Content.ReadAsByteArrayAsync(cancellationToken);
                    await File.WriteAllBytesAsync(fullPath, bytes, cancellationToken); // This overwrites the file
                
                else
                
                    // TODO: HANDLE ME
                    throw new FileNotFoundException();
                
            
        
    

并且,要添加您需要的标题...

private void SetHeaders(HttpClient client)

    // TODO: SET ME
    client.DefaultRequestHeaders.Connection.Add("keep-alive");
    client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...");
    client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9, ...");
    client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
    client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
    client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-US"));
    client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en", .9));
    ...

旁白:您可以通过以下方式填充 CookieContainer:

    循环遍历先前响应的 cookie。 此响应可能来自 HttpAgilityPack、WebClient 或 Puppeteer(有很多选项) 手动输入(来自配置值或硬编码值)。

【讨论】:

【参考方案14】:
static void Main(string[] args)
        
            DownloadFileAsync().GetAwaiter();
 
            Console.WriteLine("File was downloaded");
            Console.Read();
        
 
        private static async Task DownloadFileAsync()
        
            WebClient client = new WebClient();
            await client.DownloadFileTaskAsync(new Uri("http://somesite.com/myfile.txt"), "mytxtFile.txt");
        

【讨论】:

【参考方案15】:

这是我的解决方案,效果很好:

public static void DownloadFile(string url, string pathToSaveFile)
        
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            // or: ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

            using (WebDownload client = new WebDownload())
            
                client.Headers["User-Agent"] = "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36";
                client.DownloadFile(new Uri(url), pathToSaveFile);
            
        
    
    public class WebDownload : WebClient
        
            protected override WebRequest GetWebRequest(Uri address)
            
                HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
                if (request != null)
                
                    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                
                return request;
            
        

【讨论】:

【参考方案16】:

在 .NET Core MVC 中,有时您可以这样做:

public async Task<ActionResult> DownloadUrl(string url) 
    return Redirect(url);

这可能假设您尝试下载的 MIME 类型设置为可由浏览器下载(例如 .mp4),因此它不会尝试重定向到网页。

【讨论】:

以上是关于如何从 C# 中的 URL 下载文件?的主要内容,如果未能解决你的问题,请参考以下文章

C# winform 如何根据URL直接下载网页保存在本地?

如何从 C# 中的网站下载文件 [关闭]

如何从 Flutter 中的 URL 下载文件并将其保存在 iOS 共享文件夹中?

如何从此 URL 从文件中获取内容?

如何从 Angular 5 中的 url 下载 pdf 文件

如何从 URL 读取 Windows 应用程序中的大量 xml 文件(从 Windows 应用程序到服务器的多个请求)c#