1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks;
class Downloader { private readonly HttpClient _httpClient = new HttpClient(); private CancellationTokenSource? _currentCts; public async Task DownloadFileAsync(string url, string filePath, IProgress<float>? progress = null) { CancelCurrentDownload(); _currentCts = new CancellationTokenSource(); CancellationToken token = _currentCts.Token; try { using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); response.EnsureSuccessStatusCode(); var totalBytes = response.Content.Headers.ContentLength ?? -1; using var contentStream = await response.Content.ReadAsStreamAsync(token); using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); var buffer = new byte[8192]; long bytesRead = 0; while (true) { token.ThrowIfCancellationRequested(); int read = await contentStream.ReadAsync(buffer, token); if (read == 0) break; await fileStream.WriteAsync(buffer.AsMemory(0, read), token); bytesRead += read; if (totalBytes > 0 && progress != null) { progress.Report((float)bytesRead / totalBytes); } } Console.WriteLine("下载完成"); } catch (OperationCanceledException) { Console.WriteLine("下载被取消"); if (File.Exists(filePath)) File.Delete(filePath); throw; } } public void CancelCurrentDownload() { if (_currentCts != null && !_currentCts.IsCancellationRequested) { _currentCts.Cancel(); _currentCts.Dispose(); _currentCts = null; } } }
class Program { static async Task Main() { var downloader = new Downloader(); var cts = new CancellationTokenSource(); cts.CancelAfter(5000); try { await downloader.DownloadFileAsync( "https://example.com/largefile.zip", "downloaded.zip", new Progress<float>(p => Console.WriteLine($"进度: {p:P0}") ), cts.Token); } catch (OperationCanceledException) { Console.WriteLine("下载被外部取消"); } } }
|