ChatGPT解决这个技术问题 Extra ChatGPT

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

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

看看 System.Net.WebClient

B
Bryan Legend
using (var client = new WebClient())
{
    client.DownloadFile("http://example.com/file/song/a.mpeg", "a.mpeg");
}

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

包括这个命名空间

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

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

使用 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
p
petrzjunior
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...
J
Jonas_Hess

完成课程以在将状态打印到控制台时下载文件。

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
S
Surendra Shrestha

尝试使用这个:

private void downloadFile(string url)
{
     string file = System.IO.Path.GetFileName(url);
     WebClient cln = new WebClient();
     cln.DownloadFile(url, file);
}

文件将保存在哪里?
该文件将保存在可执行文件所在的位置。如果您想要完整路径,请使用完整路径和文件(这是要下载的项目的文件名)
t
turgay

您也可以在 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/


h
haZya

使用 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(),因为根据我的经验,会返回太多误报。
除非您在 LAN 等计算机网络中,否则 GetIsNetworkAvailable() 将始终正确返回。在这种情况下,您可以使用 System.Net.WebClient().OpenRead(Uri) 方法来查看它是否在给定默认 URL 时返回。请参阅WebClient.OpenRead()
k
kofifus

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.00}Mbps");
  }
  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
}

D
Davide Briscese

从 .NET 6 (source - 11/2021) 开始,WebRequest、WebClient 和 ServicePoint 已过时。

请改用 System.Net.Http.HttpClient 类:

using (var client = new HttpClient())
{
    using (var s = client.GetStreamAsync("https://via.placeholder.com/150"))
    {
        using (var fs = new FileStream("localfile.jpg", FileMode.OpenOrCreate))
        {
            s.Result.CopyTo(fs);
        }
    }
}

D
Darshit Gandhi

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

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);
    }

在我尝试此代码的情况下,路径为空,文件名也为空,不知道我能做什么
K
Kiran Shahi

根据我的研究,我发现 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 文件夹中。请阅读代码中的注释以了解上述代码的作用。


K
Kreshnik

您可能需要在文件下载期间了解状态并更新 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");
}

对于那些不熟悉异步操作和跨线程调用的人来说,一些关于代码语句目的的注释会很有帮助。
C
Cryptc

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

// 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(很多选项)手动条目(来自配置值或硬编码值)。


M
M22
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");
        }

O
O Thạnh Ldt

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

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

C
Cryptc

在 .NET Core MVC 中,有时您可以简单地执行以下操作:

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

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


K
Kevin Smith

有很多答案,但这是我最近用于 .NET 6 或更高版本的解决方案。

using var httpClient = new HttpClient();

var tempPath = Path.GetTempFileName();

await using var s = await HttpClient.GetStreamAsync(pdfFilePath);

await using var fs = File.OpenWrite(tempPath);

await s.CopyToAsync(fs);