From 00ccc313e01251619eefd33d18185acc7000afd8 Mon Sep 17 00:00:00 2001 From: dong <1278815766@qq.com> Date: Thu, 26 Jun 2025 19:05:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A8=E6=80=81=E9=85=8D=E7=BD=AE=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.config | 4 ++ CheckDownload.csproj | 3 +- Form1.cs | 105 ++++++++++++++++++++++++------------------- 3 files changed, 66 insertions(+), 46 deletions(-) diff --git a/App.config b/App.config index ed9893e..0256a61 100644 --- a/App.config +++ b/App.config @@ -15,4 +15,8 @@ + + + + \ No newline at end of file diff --git a/CheckDownload.csproj b/CheckDownload.csproj index ec7963b..83348a0 100644 --- a/CheckDownload.csproj +++ b/CheckDownload.csproj @@ -125,6 +125,7 @@ + @@ -176,7 +177,7 @@ - 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + 这台计算机上缺少此项目引用的 NuGet 程序包。使用"NuGet 程序包还原"可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 diff --git a/Form1.cs b/Form1.cs index 0c3250e..e65a45a 100644 --- a/Form1.cs +++ b/Form1.cs @@ -22,6 +22,7 @@ using Newtonsoft.Json.Linq; using System.Collections.Concurrent; using System.Diagnostics; +using System.Configuration; namespace CheckDownload { @@ -57,7 +58,9 @@ namespace CheckDownload // 网络优化: 备用DNS服务列表,提高解析成功率 private static readonly List _dnsServers = new List { "223.5.5.5", "119.29.29.29" }; // 最大并发下载数量 - private static readonly int MaxConcurrentDownloads = 2; + private static readonly int MaxConcurrentDownloads = int.TryParse(ConfigurationManager.AppSettings["MaxConcurrentDownloads"], out var mcd) ? mcd : 4; + // 最大下载重试次数 + private static readonly int MaxDownloadRetries = int.TryParse(ConfigurationManager.AppSettings["MaxDownloadRetries"], out var mdr) ? mdr : 2; // 用于存储下载的文件数据 private Dictionary _downloadedFiles = new Dictionary(); // 已完成的下载数量 @@ -202,17 +205,33 @@ namespace CheckDownload } UpdateStatus("下载并验证文件..."); - _totalCount = compareResult.Count; - await DownloadAndVerifyFiles(compareResult); - UpdateProgressValue(100); + // 根据路径长度排序,优先下载小文件/浅层文件,可加其它排序规则 + var orderedFileList = compareResult.OrderBy(k => k.Key.Length) + .ToDictionary(k => k.Key, v => v.Value); - // 更新成功后清理临时文件夹 - CleanupTempDirectory(); + _totalCount = orderedFileList.Count; + _completedCount = 0; + _downloadedFiles.Clear(); + var failedFiles = new ConcurrentDictionary(); + + await PerformDownloads(orderedFileList, failedFiles); + + if (!failedFiles.IsEmpty) + { + UpdateStatus($"有 {failedFiles.Count} 个文件下载失败,开始重试..."); + var stillFailing = await RetryFailedFilesAsync(new Dictionary(failedFiles)); + if (stillFailing.Any()) + { + UpdateStatus($"重试后仍有 {stillFailing.Count} 个文件下载失败。"); + } + } + + if (_completedCount == 0 && orderedFileList.Count > 0) + { + throw new Exception("所有文件下载失败。"); + } - // 显示更新完成并等待3秒 - UpdateStatus("更新完成"); - await Task.Delay(3000); - this.Close(); + await VerifyAndSaveAllFiles(); } catch (Exception ex) { @@ -539,7 +558,7 @@ namespace CheckDownload UpdateStatus($"使用主域名下载文件..."); - var request = new HttpRequestMessage(HttpMethod.Get, authUrl); + var request = new HttpRequestMessage(HttpMethod.Get, authUrl) { Version = HttpVersion.Version11 }; request.Headers.Add("User-Agent", "CheckDownload/1.0"); using (var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) @@ -574,7 +593,7 @@ namespace CheckDownload UpdateStatus($"使用备用域名下载文件..."); - var request = new HttpRequestMessage(HttpMethod.Get, authUrl); + var request = new HttpRequestMessage(HttpMethod.Get, authUrl) { Version = HttpVersion.Version11 }; request.Headers.Add("User-Agent", "CheckDownload/1.0"); using (var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) @@ -618,7 +637,7 @@ namespace CheckDownload { string authUrl = GenerateAuthUrl($"http://{OneDriveMainDomain}{OneDrivePath}", fileName); - var request = new HttpRequestMessage(HttpMethod.Get, authUrl); + var request = new HttpRequestMessage(HttpMethod.Get, authUrl) { Version = HttpVersion.Version11 }; request.Headers.Add("User-Agent", "CheckDownload/1.0"); using (var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) @@ -647,7 +666,7 @@ namespace CheckDownload { string authUrl = GenerateAuthUrl($"http://{OneDriveBackupDomain}{OneDrivePath}", fileName); - var request = new HttpRequestMessage(HttpMethod.Get, authUrl); + var request = new HttpRequestMessage(HttpMethod.Get, authUrl) { Version = HttpVersion.Version11 }; request.Headers.Add("User-Agent", "CheckDownload/1.0"); using (var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) @@ -681,10 +700,9 @@ namespace CheckDownload /// 重试后仍然失败的文件字典 private async Task> RetryFailedFilesAsync(Dictionary failedFiles) { - const int maxRetries = 2; var filesToRetry = new Dictionary(failedFiles); - for (int i = 0; i < maxRetries && filesToRetry.Any(); i++) + for (int i = 0; i < MaxDownloadRetries && filesToRetry.Any(); i++) { UpdateStatus($"第 {i + 1} 次重试,剩余 {filesToRetry.Count} 个文件..."); var failedThisRound = new ConcurrentDictionary(); @@ -693,7 +711,7 @@ namespace CheckDownload filesToRetry = new Dictionary(failedThisRound); - if (filesToRetry.Any() && i < maxRetries - 1) + if (filesToRetry.Any() && i < MaxDownloadRetries - 1) { UpdateStatus($"等待 3 秒后进行下一次重试..."); await Task.Delay(3000); @@ -715,7 +733,7 @@ namespace CheckDownload try { var requestUri = $"http://{dnsServer}/resolve?name={domain}&type=1&short=1"; - var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + var request = new HttpRequestMessage(HttpMethod.Get, requestUri) { Version = HttpVersion.Version11 }; request.Headers.Add("User-Agent", "CheckDownload/1.0"); request.Headers.Host = dnsServer; @@ -747,31 +765,31 @@ namespace CheckDownload private async Task VerifyAndSaveAllFiles() { UpdateStatus("正在校验文件..."); - var failedFiles = new List(); - var filesForScripting = new List<(string original, string newFile)>(); - int processedCount = 0; + var failedFiles = new ConcurrentBag(); + var filesForScripting = new ConcurrentBag<(string original, string newFile)>(); + int totalFiles = _downloadedFiles.Count; + int completed = 0; + var semaphore = new SemaphoreSlim(Environment.ProcessorCount); - foreach (var item in _downloadedFiles) + var tasks = _downloadedFiles.Select(async item => { - string relativePath = item.Key; - string expectedMd5 = item.Value; - string tempFilePath = Path.Combine(_tempDirectory, relativePath); - + await semaphore.WaitAsync(); try { - processedCount++; - UpdateStatus($"正在校验和保存文件 ({processedCount}/{totalFiles}): {relativePath}"); + string relativePath = item.Key; + string expectedMd5 = item.Value; + string tempFilePath = Path.Combine(_tempDirectory, relativePath); string actualMd5 = CalculateMD5FromFile(tempFilePath); if (actualMd5 != expectedMd5.ToLower()) { - throw new Exception($"MD5校验失败 (期望: {expectedMd5}, 实际: {actualMd5})"); + failedFiles.Add(relativePath); + return; } string localPath = Path.Combine(_baseDirectory, relativePath); string localDir = Path.GetDirectoryName(localPath); - if (!Directory.Exists(localDir)) { Directory.CreateDirectory(localDir); @@ -782,31 +800,28 @@ namespace CheckDownload string backupPath = localPath + ".new"; File.Move(tempFilePath, backupPath); filesForScripting.Add((localPath, backupPath)); - UpdateStatus($"文件 {relativePath} 正在被占用,将在程序重启后更新"); - } - else - { - UpdateStatus($"文件 {relativePath} 已更新"); } - int percentage = 95 + (int)(processedCount * 5.0 / totalFiles); - UpdateProgressValue(Math.Min(100, percentage)); } - catch (Exception ex) + finally { - UpdateStatus($"文件校验失败: {relativePath} - {ex.Message}"); - failedFiles.Add(relativePath); + int done = Interlocked.Increment(ref completed); + int percentage = 95 + (int)(done * 5.0 / totalFiles); + UpdateProgressValue(Math.Min(100, percentage)); + semaphore.Release(); } - } + }); + + await Task.WhenAll(tasks); if (filesForScripting.Any()) { - CreateReplaceScriptForAll(filesForScripting); + CreateReplaceScriptForAll(filesForScripting.ToList()); } - foreach (var failedFile in failedFiles) + foreach (var failed in failedFiles) { - _downloadedFiles.Remove(failedFile); + _downloadedFiles.Remove(failed); } if (failedFiles.Count > 0) @@ -1009,7 +1024,7 @@ namespace CheckDownload { var ipUrl = signedUrl.Replace(signedUri.Host, ip); - var request = new HttpRequestMessage(HttpMethod.Get, ipUrl); + var request = new HttpRequestMessage(HttpMethod.Get, ipUrl) { Version = HttpVersion.Version11 }; request.Headers.Host = signedUri.Host; using (var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)) {