Как использовать HttpWebRequest/Response для загрузки двоичного (.exe) файла с веб-сервера?
Я пишу программу, которая должна загрузить .exe
файл с веб-сайта, а затем сохраните его на жестком диске. .exe
хранится на моем сайте, и его URL-адрес выглядит следующим образом (это не настоящий URI, только тот, который я создал для целей этого вопроса):
http://www.mysite.com/calc.exe
После многих поисков в сети и поиска примеров, вот код, который я придумал:
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(http://www.mysite.com/calc.exe);
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream);
string s = streamReader.ReadToEnd();
Как вы можете видеть, я использую StreamReader
класс для чтения данных. После звонка ReadToEnd
Содержит ли потоковая программа (двоичное) содержимое моего.exe? Могу ли я просто написать содержание StreamReader
в файл (с именем calc.exe), и я успешно загрузил.exe?
Мне интересно почему StreamReader
ReadToEnd
возвращает строку В моем случае эта строка будет двоичным содержимым calc.exe?
5 ответов
WebClient - лучший способ загрузить файл. Но вы можете использовать следующий метод для асинхронной загрузки файла с веб-сервера.
private static void DownloadCurrent()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("[url to download]");
webRequest.Method = "GET";
webRequest.Timeout = 3000;
webRequest.BeginGetResponse(new AsyncCallback(PlayResponeAsync), webRequest);
}
private static void PlayResponeAsync(IAsyncResult asyncResult)
{
long total = 0;
long received = 0;
HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;
try
{
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult))
{
byte[] buffer = new byte[1024];
FileStream fileStream = File.OpenWrite("[file name to write]");
using (Stream input = webResponse.GetResponseStream())
{
total = input.Length;
long size = input.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
received += size;
size = input.Read(buffer, 0, buffer.Length);
}
}
fileStream.Flush();
fileStream.Close();
}
}
catch (Exception ex)
{
}
}
Здесь есть похожая тема - Как загрузить файл с использованием классов HttpWebRequest и HttpWebResponse (файлы cookie, учетные данные и т. Д.)
StreamReader является реализацией для чтения текста, т.е. его следует использовать для чтения текстовых данных, а не двоичных данных. В вашем случае вы должны напрямую использовать основной поток ответов.
Для загрузки файла самый простой способ - использовать метод WebClient.DownloadFile.
Это должно непосредственно сохранить файл на вашем жестком диске.
using System.Net;
using (WebClient webClient = new WebClient ())
{
webClient.DownloadFile("http://www.mysite.com/calc.exe", "calc.exe");
}
Вместо того, чтобы использовать StreamReader
Вы должны действительно позвонить Read()
метод вашего Stream
объект. Это попросит вас заполнить буфер byte[] данными для чтения, которые затем вы сможете записать на диск, используя StreamWriter
или же FileStream
,
Возможно, я немного опоздал, но у меня была та же проблема с файлами размером 0 КБ, если они не работали в режиме отладки. Это может быть относительно простой ответ, но отключение "Константы отладки" в разделе "Свойства" решило эту проблему для меня.
Я создал класс с событиями, чтобы вы могли отслеживать прогресс загрузки:
using System;
using System.IO;
using System.Net;
using System.Net.Mime;
//event examples: https://www.tutorialsteacher.com/csharp/csharp-event
public class HttpWebRequestDownload
{
private long _totalBytesLength = 0;
private long _transferredBytes = 0;
private int _transferredPercents => (int)((100 * _transferredBytes) / _totalBytesLength);
private string _defaultDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
public string downloadedFilePath = String.Empty;
public HttpWebRequestDownload(){
//Windows 7 fix
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
}
public void DownloadFile(string url, string destinationDirectory = default)
{
string filename = "";
if (destinationDirectory == default)
destinationDirectory = _defaultDirectory;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Cache-Control", "no-cache");
request.Headers.Add("Cache-Control", "no-store");
request.Headers.Add("Cache-Control", "max-age=1");
request.Headers.Add("Cache-Control", "s-maxage=1");
request.Headers.Add("Pragma", "no-cache");
request.Headers.Add("Expires", "-1");
if (!Directory.Exists(destinationDirectory))
{
Directory.CreateDirectory(destinationDirectory);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponseAsync().Result)
{
_totalBytesLength = response.ContentLength;
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;
}
using (Stream responseStream = response.GetResponseStream())
using (FileStream fileStream = File.Create(System.IO.Path.Combine(destinationDirectory, filename)))
{
byte[] buffer = new byte[1024*1024]; // 1MB buffer
ProgressEventArgs eventArgs = new ProgressEventArgs(_totalBytesLength);
int size = responseStream.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
_transferredBytes += size;
size = responseStream.Read(buffer, 0, buffer.Length);
eventArgs.UpdateData(_transferredBytes, _transferredPercents);
OnDownloadProgressChanged(eventArgs);
}
}
}
downloadedFilePath = Path.Combine(destinationDirectory, filename);
OnDownloadFileCompleted(EventArgs.Empty);
}
catch (Exception e)
{
OnError($"{e.Message} => {e?.InnerException?.Message}");
}
}
//events
public event EventHandler<ProgressEventArgs> DownloadProgressChanged;
public event EventHandler DownloadFileCompleted;
public event EventHandler<string> Error;
public class ProgressEventArgs : EventArgs
{
public long TransferredBytes { get; set; }
public int TransferredPercents { get; set; }
public long TotalBytesLength { get; set; }
public ProgressEventArgs(long transferredBytes, int transferredPercents, long totalBytesLength)
{
TransferredBytes = transferredBytes;
TransferredPercents = transferredPercents;
TotalBytesLength = totalBytesLength;
}
public ProgressEventArgs(long totalBytesLength)
{
this.TotalBytesLength = totalBytesLength;
}
public void UpdateData(long transferredBytes, int transferredPercents)
{
TransferredBytes = transferredBytes;
TransferredPercents = transferredPercents;
}
}
protected virtual void OnDownloadProgressChanged(ProgressEventArgs e)
{
DownloadProgressChanged?.Invoke(this, e);
}
protected virtual void OnDownloadFileCompleted(EventArgs e)
{
DownloadFileCompleted?.Invoke(this, e);
}
protected virtual void OnError(string errorMessage)
{
Error?.Invoke(this, errorMessage);
}
}
Вот пример тестирования:
static void Main(string[] args)
{
HttpWebRequestDownload hDownload = new HttpWebRequestDownload();
string downloadUrl = "http://speedtest.tele2.net/10MB.zip";
hDownload.DownloadProgressChanged += HDownloadOnDownloadProgressChanged;
hDownload.DownloadFileCompleted += delegate(object o, EventArgs args)
{
Debug.WriteLine("Download finished and saved to: "+hDownload.downloadedFilePath);
};
hDownload.Error += delegate(object o, string errMessage) { Debug.WriteLine("Error has occured !! => "+errMessage); };
hDownload.DownloadFile(downloadUrl);
}
private void HDownloadOnDownloadProgressChanged(object sender, HttpWebRequestDownload.ProgressEventArgs e)
{
Debug.WriteLine("progress: "+e.TransferredBytes+" => "+e.TransferredPercents);
}