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

vbr*_*oto 322 c# downloadfile

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

Raj*_*mar 442

using (var client = new WebClient())
{
    client.DownloadFile("http://example.com/file/song/a.mpeg", "a.mpeg");
}
Run Code Online (Sandbox Code Playgroud)

  • 有史以来最好的解决方案,但我想添加一条重要的行'client.Credentials = new NetworkCredential("UserName","Password");' (21认同)
  • WebRequest、WebClient 和 ServicePoint 在 **.Net 6** 链接中已过时 --> https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/6.0/webrequest-deprecated (16认同)
  • @AkbarAsghari 是正确的。请参阅下面的[我的答案](/sf/answers/5036499611/),例如使用 HttpClient 类。 (6认同)
  • 一个受欢迎的副作用:此方法还支持本地文件作为第一个参数 (3认同)
  • @copa017:或者是一个危险的情况,例如,如果 URL 是用户提供的并且 C# 代码在 Web 服务器上运行。 (3认同)

Say*_*yka 167

包括此命名空间

using System.Net;
Run Code Online (Sandbox Code Playgroud)

异步下载并放入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;
}
Run Code Online (Sandbox Code Playgroud)

  • 大多数人在下载时都更喜欢进度条.所以我写了最简单的方法来做到这一点.这可能不是答案,但它符合Stackoverflow的要求.那是为了帮助别人. (70认同)
  • 问题要求最简单的方法.制作更复杂并不是最简单的. (12认同)
  • @Jessedegans 已经有一个答案展示了如何在没有进度条的情况下简单地下载。这就是为什么我写了一个有助于异步下载和进度条实现的答案 (4认同)
  • 如果您忽略进度条,这就像其他答案一样简单.此答案还包括命名空间并使用I/O的异步.此问题并不是要求最简单的方法,只是一种简单的方法.:) (3认同)

Dav*_*ese 90

WebRequestWebClient、 和从 .NET 6ServicePoint开始已过时来源- 11/2021)。

使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

相同代码的异步版本:

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

Run Code Online (Sandbox Code Playgroud)


vbr*_*oto 72

用途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())
{
    string myStringWebResource = remoteUri + fileName;
    // Download the Web resource and save it into the current filesystem folder.
    myWebClient.DownloadFile(myStringWebResource, fileName);        
}
Run Code Online (Sandbox Code Playgroud)

  • WebClient 已过时,请参阅 https://github.com/dotnet/runtime/issues/33125 (2认同)

小智 40

using System.Net;

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

  • 欢迎来到SO!通常,对已经有很高评价答案的现有和旧问题发布低质量答案并不是一个好主意. (31认同)
  • 我从seanb的评论中找到了答案,但我真的更喜欢这种"低质量"的答案.它完整​​(使用声明),简洁易懂.作为一个老问题是无关紧要的,恕我直言. (27认同)
  • 但它认为使用Using的答案要好得多,因为我认为WebClient应该在使用后处理掉.将其放入使用中可确保其处理. (21认同)
  • 它与此代码示例中的disposes无关......这里的using语句只显示要使用的命名空间,而不是WebClient用于处理... (5认同)

Jon*_*ess 16

在将状态打印到控制台时完成下载文件的类.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

static void Main(string[] args)
{
    var success = FileDownloader.DownloadFile(fileUrl, fullPathWhereToSave, timeoutInMilliSec);
    Console.WriteLine("Done  - success: " + success);
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)


kof*_*fus 12

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);
}
Run Code Online (Sandbox Code Playgroud)

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

DownoadFileAsync我为、GetToStringAsync和提出了一组 C# 9.0 扩展类PostToStringAsync

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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

使用方法:

// 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
}
Run Code Online (Sandbox Code Playgroud)


小智 9

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

样品:

    webClient.DownloadFileAsync(new Uri("http://www.example.com/file/test.jpg"), "test.jpg");
Run Code Online (Sandbox Code Playgroud)

欲获得更多信息:

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


Kev*_*ith 8

这是我最近用于 .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);
Run Code Online (Sandbox Code Playgroud)


Sur*_*tha 7

试试这个:

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

  • 文件将保存在哪里? (2认同)

小智 6

检查网络连接,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");
    }                  
}
Run Code Online (Sandbox Code Playgroud)


小智 6

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

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);
    }
Run Code Online (Sandbox Code Playgroud)