Каков простой способ загрузки файла по URL-адресу?
Как загрузить файл по URL-адресу в C #?
Ответы (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;
}
Используйте 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);
}
Полный класс для загрузки файла при печати статуса на консоль.
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
в этом контексте?
- 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);
}
Также вы можете использовать метод 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/
Проверьте сетевое соединение с помощью 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()
, поскольку, по моему опыту, возвращает слишком много ложных срабатываний.
- person Cherona; 21.01.2020
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);
}
В ходе своего исследования я обнаружил, что 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
папку каталога проекта. Прочтите комментарий в коде, чтобы понять, что делает код выше.
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
Возможно, вам потребуется узнать статус и обновить 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");
}
Если вам нужно установить Заголовки и Файлы 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 следующим образом:
- Looping through the cookies of a previous Response.
- This response could be from HttpAgilityPack, or WebClient, or Puppeteer (lots of options)
- Записи вручную (из значений конфигурации или жестко заданных значений).
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