using System.IO; using System.Net.Http; using System.Windows.Controls; namespace Zerolauncher.dialog { /// /// DownloadControl.xaml 的交互逻辑 /// public partial class DownloadControl : UserControl { const string cache_dir = "./.cache/auto.cache"; public DownloadControl() { InitializeComponent(); } private void OnError(Exception ex) { // UnityEngine.Debug.Log("捕获异常 >>> " + ex); } public async Task Download(string fileUrl) { using (HttpClient client = new HttpClient()) { // 获取文件大小 HttpResponseMessage responseHead = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, fileUrl)); long? contentLength = responseHead.Content.Headers.ContentLength; Console.WriteLine($"文件大小:{contentLength} 字节"); // 计算块大小 int blockSize = 1024 * 1024; // 1MB int blockCount = (int)Math.Ceiling((double)contentLength / blockSize); // 创建SemaphoreSlim以限制同时进行的下载任务的数量 SemaphoreSlim semaphore = new SemaphoreSlim(4); // 最多允许4个并发下载任务 using (FileStream fileStream = new FileStream(cache_dir, FileMode.Create, FileAccess.Write, FileShare.None, blockSize, true)) { // 创建任务列表 Task[] tasks = new Task[blockCount]; for (int i = 0; i < blockCount; i++) { int blockNumber = i; tasks[i] = Task.Run(async () => { await semaphore.WaitAsync(); // 等待获取许可 try { // 计算当前块的范围 var start = blockNumber * blockSize; var end = (blockNumber == blockCount - 1) ? contentLength - 1 : start + blockSize - 1; // 设置请求头,请求指定范围的数据 var request = new HttpRequestMessage { RequestUri = new Uri(fileUrl), Method = HttpMethod.Get }; request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end); // 下载当前块 using (HttpResponseMessage response = await client.SendAsync(request)) { response.EnsureSuccessStatusCode(); byte[] buffer = await response.Content.ReadAsByteArrayAsync(); await fileStream.WriteAsync(buffer, 0, buffer.Length); } // 显示下载进度 double percent = (double)(blockNumber + 1) / blockCount * 100; Console.WriteLine($"已下载:{percent:F2}%"); } finally { semaphore.Release(); // 释放许可 } }); } // 等待所有任务完成 await Task.WhenAll(tasks); } } Console.WriteLine("下载完成!"); } private void OnUpdate(long size, long count) { } private void OnDone(byte[] data) { } private void OnDestroy() { } } }