Downloader类别:
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace Download_Http
{
class Downloader
{
public delegate void DownloadProgressHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
public static class DownloadWithProgress
{
public static async Task ExecuteAsync(HttpClient httpClient, string downloadPath, string destinationPath, DownloadProgressHandler progress, Func<HttpRequestMessage> requestMessageBuilder = null)
{
if (requestMessageBuilder != null)
GetDefaultRequestBuilder(downloadPath);
var download = new HttpClientDownloadWithProgress(httpClient, destinationPath, requestMessageBuilder);
download.ProgressChanged += progress;
await download.StartDownload();
download.ProgressChanged -= progress;
}
private static Func<HttpRequestMessage> GetDefaultRequestBuilder(string downloadPath)
{
return () => new HttpRequestMessage(HttpMethod.Get, downloadPath);
}
}
internal class HttpClientDownloadWithProgress
{
private readonly HttpClient _httpClient;
private readonly string _destinationFilePath;
private readonly Func<HttpRequestMessage> _requestMessageBuilder;
private int _bufferSize = 8192;
public event DownloadProgressHandler ProgressChanged;
public HttpClientDownloadWithProgress(HttpClient httpClient, string destinationFilePath, Func<HttpRequestMessage> requestMessageBuilder)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_destinationFilePath = destinationFilePath ?? throw new ArgumentNullException(nameof(destinationFilePath));
_requestMessageBuilder = requestMessageBuilder ?? throw new ArgumentNullException(nameof(requestMessageBuilder));
}
public async Task StartDownload()
{
var requestMessage = _requestMessageBuilder.Invoke();
var response = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);
await DownloadAsync(response);
}
private async Task DownloadAsync(HttpResponseMessage response)
{
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength;
using (var contentStream = await response.Content.ReadAsStreamAsync())
await ProcessContentStream(totalBytes, contentStream);
}
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream)
{
var totalBytesRead = 0L;
var readCount = 0L;
var buffer = ArrayPool<byte>.Shared.Rent(_bufferSize);
var isMoreToRead = true;
using (var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, _bufferSize, true))
{
do
{
var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
isMoreToRead = false;
ReportProgress(totalDownloadSize, totalBytesRead);
continue;
}
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
readCount += 1;
if (readCount % 100 == 0)
ReportProgress(totalDownloadSize, totalBytesRead);
}
while (isMoreToRead);
}
ArrayPool<byte>.Shared.Return(buffer);
}
private void ReportProgress(long? totalDownloadSize, long totalBytesRead)
{
double? progressPercentage = null;
if (totalDownloadSize.HasValue)
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
ProgressChanged?.Invoke(totalDownloadSize, totalBytesRead, progressPercentage);
}
}
}
}
使用它的形式1:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Download_Http
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private async void button1_Click(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
const string url = "https://speed.hetzner.de/100MB.bin";
Downloader.DownloadProgressHandler progressHandler = null;
await Downloader.DownloadWithProgress.ExecuteAsync(client,url, @"D:\Test\100MB.bin", progressHandler, () =>
{
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
requestMessage.Headers.Accept.TryParseAdd("application/octet-stream");
return requestMessage;
});
}
}
}
它正在下载文件,但我如何向progressBar1报告进度?我在form1设计器中有一个ProgressBar控件。我如何向标签报告下载速度和其他计算结果?
如何创建进度更改事件和完成事件?
1条答案
按热度按时间mf98qq941#
您可以使用
Progress
对象,该对象会自动将进度事件封送回UI线程。