Как загрузить файл по URL-адресу в C #?

Каков простой способ загрузки файла по URL-адресу?


person vbroto    schedule 21.11.2008    source источник
comment
Взгляните на System.Net.WebClient   -  person seanb    schedule 21.11.2008


Ответы (13)


Включить это пространство имен

using System.Net;

Загрузите Асинхронно и поместите ProgressBar, чтобы показать статус загрузки в самой теме пользовательского интерфейса.

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;
}
person Abdul Saleem    schedule 21.03.2015
comment
Вопрос требует простейшего пути. Усложнение не делает его самым простым. - person Enigmativity; 15.04.2015
comment
Большинство людей предпочли бы индикатор выполнения при загрузке. Итак, я просто написал самый простой способ сделать это. Возможно, это не ответ, но он соответствует требованиям Stackoverflow. То есть помочь кому-то. - person Abdul Saleem; 15.04.2015
comment
Это так же просто, как и другой ответ, если вы просто опустите индикатор выполнения. Этот ответ также включает пространство имен и использует асинхронный режим для ввода-вывода. Также вопрос не о простейшем способе, а просто о простом способе. :) - person Josh; 10.10.2018
comment
Я думаю, что было бы лучше дать 2 ответа, один простой и один с индикатором выполнения - person Jesse de gans; 29.02.2020
comment
@Jessedegans. Уже есть ответ, который показывает, как просто загружать без индикатора выполнения. Вот почему я написал ответ, который помогает с асинхронной загрузкой и реализацией индикатора выполнения. - person Abdul Saleem; 29.02.2020

Используйте 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);        
}
person vbroto    schedule 21.11.2008
comment
WebClient устарел, см. github.com/dotnet/runtime/issues/33125 - person kofifus; 22.04.2021

Полный класс для загрузки файла при печати статуса на консоль.

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();
}
person Jonas_Hess    schedule 11.03.2016
comment
Не могли бы вы объяснить, почему вы используете SemaphoreSlim в этом контексте? - person mmushtaq; 31.10.2016

Попробуйте использовать это:

private void downloadFile(string url)
{
     string file = System.IO.Path.GetFileName(url);
     WebClient cln = new WebClient();
     cln.DownloadFile(url, file);
}
person Surendra Shrestha    schedule 11.01.2018
comment
где файл будет сохранен? - person Irshad Babar; 31.03.2019
comment
Файл будет сохранен в том месте, где находится исполняемый файл. Если вам нужен полный путь, используйте полный путь вместе с файлом (который является именем файла для загрузки) - person Surendra Shrestha; 17.04.2019

Также вы можете использовать метод DownloadFileAsync в классе WebClient. Он загружает в локальный файл ресурс с указанным URI. Также этот метод не блокирует вызывающий поток.

Образец:

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

Для получения дополнительной информации:

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

person turgay    schedule 16.06.2014

Проверьте сетевое соединение с помощью 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");
    }                  
}
person haZya    schedule 15.02.2016
comment
Я бы посоветовал не использовать GetIsNetworkAvailable(), поскольку, по моему опыту, возвращает слишком много ложных срабатываний. - person Cherona; 21.01.2020
comment
Если вы не находитесь в компьютерной сети, такой как LAN, GetIsNetworkAvailable() всегда будет возвращаться правильно. В таком случае вы можете использовать метод System.Net.WebClient().OpenRead(Uri), чтобы узнать, вернется ли он при заданном URL-адресе по умолчанию. См. WebClient.OpenRead () - person haZya; 21.01.2020

Код ниже содержит логику для загрузки файла с оригинальным именем

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);
    }
person Darshit Gandhi    schedule 30.10.2017

В ходе своего исследования я обнаружил, что 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 папку каталога проекта. Прочтите комментарий в коде, чтобы понять, что делает код выше.

person Kiran Shahi    schedule 23.09.2019

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

Приведенный выше код представляет собой скорее схему без обработки ошибок, в частности, обработка исключений для GetAsync нетривиальна.
Ниже представлено полное решение для Get, Post и Get to file, реализованное как методы расширения:

namespace System.Net.Http {
  public static class ExtensionMethods {

    public static async Task<(bool Success, string? ErrorMessage, HttpStatusCode? HttpStatusCode, WebExceptionStatus? WebExceptionStatus)> GetToFileAsync(this HttpClient httpClient, string requestUri, string fileToWriteTo, CancellationTokenSource? cts = null) {
      var created = false;
      try {
        using HttpResponseMessage? response = cts is null
            ? await httpClient.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead)
            : await httpClient.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cts.Token);

        if (!response.IsSuccessStatusCode) return (false, response.ReasonPhrase, null, null);
        using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync();

        using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create);
        created = true;
        await streamToReadFrom.CopyToAsync(streamToWriteTo);
        return (true, null, response.StatusCode, null);

      } catch (Exception ex) {
        if (created) try { File.Delete(fileToWriteTo); } catch { };
        var (errorMessage, HttpStatusCode, WebExceptionStatus) = ProcessHttpException(ex);
        return (false, errorMessage, HttpStatusCode, WebExceptionStatus);
      }
    }

    public static async Task<(string? ResponseAsString, string? ErrorMessage, HttpStatusCode? HttpStatusCode, WebExceptionStatus? WebExceptionStatus)> RequestAsync(this HttpClient httpClient, Uri requestUri, HttpContent? postBuffer = null, CancellationTokenSource? cts = null) {
      try {
        using HttpResponseMessage? response = postBuffer is null
          ? (cts is null ? await httpClient.GetAsync(requestUri) : await httpClient.GetAsync(requestUri, cts.Token))
          : (cts is null ? await httpClient.PostAsync(requestUri, postBuffer) : await httpClient.PostAsync(requestUri, postBuffer, cts.Token));

        if (!response.IsSuccessStatusCode) return (null, response.ReasonPhrase, response.StatusCode, null);
        var respString = await response.Content.ReadAsStringAsync();
        return (respString, "", response.StatusCode, null);

      } catch (Exception ex) {
        var (errorMessage, HttpStatusCode, WebExceptionStatus) = ProcessHttpException(ex);
        return (null, errorMessage, HttpStatusCode, WebExceptionStatus);
      }
    }

    static (string? ErrorMessage, HttpStatusCode? HttpStatusCode, WebExceptionStatus? WebExceptionStatus) ProcessHttpException(Exception exception) {
      if (exception is WebException ex1 && ex1.Status == WebExceptionStatus.ProtocolError) {
        using HttpWebResponse? httpResponse = (HttpWebResponse?)ex1.Response;
        return (httpResponse?.StatusDescription, httpResponse?.StatusCode, ex1.Status);
      
      } else if (exception is WebException ex2) {
        return (ex2.FullMessage(), null, ex2.Status);

      } else if (exception is TaskCanceledException ex3 && ex3.InnerException is TimeoutException) { 
        return (ex3.InnerException.FullMessage(), null, WebExceptionStatus.Timeout);

      } else if (exception is TaskCanceledException ex4) {
        return (ex4.FullMessage(), null, WebExceptionStatus.RequestCanceled);

      } else {
        return (exception.FullMessage(), null, null);
      }
    }
  }
}

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 (Success, ErrorMessage, HttpStatusCode, WebExceptionStatus) 
  = await httpClient.GetToFileAsync(uri, localFile);
if (Success) ...
else // examine ErrorMessage, HttpStatusCode and WebExceptionStatus

// http get
var (ResponseAsString, ErrorMessage, HttpStatusCode, WebExceptionStatus) 
  = await httpClient.RequestAsync(uri);
if (ResponseAsString is not null) ...
else // examine ErrorMessage, HttpStatusCode and WebExceptionStatus

// http post
var (ResponseAsString, ErrorMessage, HttpStatusCode, WebExceptionStatus) 
 = await httpClient.RequestAsync(uri, postBuffer);
if (ResponseAsString is not null) ...
else // examine ErrorMessage, HttpStatusCode and WebExceptionStatus
person kofifus    schedule 23.04.2021

Возможно, вам потребуется узнать статус и обновить ProgressBar во время загрузки файла или использовать учетные данные перед отправкой запроса.

Вот пример, который охватывает эти варианты. Использовались лямбда-нотация и строковая интерполяция:

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");
}
person Kreshnik    schedule 11.08.2017
comment
Некоторые комментарии о цели ваших кодовых операторов были бы полезны для тех, кто не знаком с асинхронными операциями и межпотоковыми вызовами. - person Suncat2000; 22.01.2021

Если вам нужно установить Заголовки и Файлы 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 следующим образом:

  1. Looping through the cookies of a previous Response.
    • This response could be from HttpAgilityPack, or WebClient, or Puppeteer (lots of options)
  2. Записи вручную (из значений конфигурации или жестко заданных значений).
person Cryptc    schedule 19.04.2021

person    schedule
comment
Лучшее решение, но я хотел бы добавить 1 важную строку «client.Credentials = new NetworkCredential (UserName, Password);» - person DmitryBoyko; 07.09.2016
comment
Приветственный побочный эффект: этот метод также поддерживает локальные файлы в качестве 1-го параметра. - person oo_dev; 22.08.2017
comment
Хотя я думаю, что WebClient кажется гораздо более простым и понятным решением. - person StormsEngineering; 02.10.2019
comment
@ copa017: Или опасный, если, например, URL-адрес предоставляется пользователем, а код C # выполняется на веб-сервере. - person Heinzi; 25.04.2020
comment
Сделайте это асинхронным: WebClient client = new WebClient (); await client.DownloadFileTaskAsync (новый Uri (somesite.com/myfile.txt), mytxtFile.txt); - person M22; 23.05.2021
comment
@ M22 асинхронный метод не возвращает Task, что означает, что вы не можете его ждать. В зависимости от вашего кода ваша программа может завершиться до завершения загрузки, оставив ее в поврежденном состоянии. - person Shashank Shekhar; 05.06.2021
comment
@ShashankShekhar ibb.co/1Xf0nrD c# static void Main(string[] args) { DownloadFileAsync().GetAwaiter(); Console.WriteLine("File loaded"); Console.Read(); } private static async Task DownloadFileAsync() { WebClient client = new WebClient(); await client.DownloadFileTaskAsync(new Uri("http://somesite.com/myfile.txt"), "mytxtFile.txt"); } Задача может быть параллельной, но не требует создания нового потока. - person M22; 06.06.2021

person    schedule
comment
Добро пожаловать в SO! Как правило, не рекомендуется публиковать некачественный ответ на существующий и старый вопрос, на который уже есть много голосов. - person ThiefMaster; 29.06.2013
comment
Я нашел свой ответ из комментария seanb, но на самом деле я предпочитаю этот некачественный ответ другим. Он полный (с использованием инструкции), краток и прост для понимания. Старый вопрос не имеет значения, ИМХО. - person Josh; 30.12.2013
comment
Но он думает, что ответ с использованием намного лучше, потому что я думаю, что WebClient следует утилизировать после использования. Помещение его внутрь использования гарантирует, что он будет утилизирован. - person Ricardo Polo Jaramillo; 11.08.2014
comment
Это не имеет ничего общего с удалением в этом примере кода ... Здесь оператор using просто показывает используемое пространство имен, нет, что WebClient используется для использования для удаления ... - person cdie; 22.03.2016