diff --git a/Form1.cs b/Form1.cs index 9b8e80b..82ce4e7 100644 --- a/Form1.cs +++ b/Form1.cs @@ -33,6 +33,9 @@ namespace CheckDownload /// 在线MD5文件名,从DNS查询获取 private string _onlineMd5File = ""; + + // 类级别变量,用于存储下载的文件数据 + private Dictionary _downloadedFiles = new Dictionary(); /// 已完成下载的文件数 private int _completedFiles = 0; @@ -345,7 +348,9 @@ namespace CheckDownload /// 下载任务 private async Task DownloadUpdatedFiles(Dictionary differences) { - // 设置进度条最大值为需要更新的文件数量 + // 重置下载状态 + _completedFiles = 0; + _downloadedFiles.Clear(); Update_Pro.Maximum = differences.Count; Update_Pro.Value = 0; @@ -361,6 +366,9 @@ namespace CheckDownload // 等待所有下载任务完成 await Task.WhenAll(downloadTasks); + + // 所有文件下载完成后统一校验和保存 + VerifyAndSaveAllFiles(); } /// @@ -371,56 +379,110 @@ namespace CheckDownload /// 下载任务 private async Task DownloadFileWithSemaphore(KeyValuePair file, SemaphoreSlim semaphore) { - // 等待信号量,控制并发数量 await semaphore.WaitAsync(); try { - // 下载并验证文件 - await DownloadAndVerifyFile(file.Key, file.Value); - // 更新进度 - UpdateProgress(); - } - catch (Exception ex) - { - UpdateStatus($"下载失败: {file.Key} - {ex.Message}"); + await DownloadToMemory(file.Key, file.Value); } finally { - // 释放信号量,允许其他下载任务执行 semaphore.Release(); } } /// - /// 下载并验证文件 + /// 下载文件到内存并暂存 /// - /// 文件的相对路径 - /// 期望的MD5值 - /// 下载任务 - private async Task DownloadAndVerifyFile(string relativePath, string expectedMd5) + private async Task DownloadToMemory(string relativePath, string expectedMd5) { - // 更新状态显示当前下载进度 - UpdateStatus($"正在下载 ({Update_Pro.Value + 1}/{Update_Pro.Maximum}): {relativePath}"); - - // 获取本地路径和临时文件路径 - string localPath = GetLocalPath(relativePath); - string tempPath = $"{localPath}.tmp"; - - // 确保目录存在 - EnsureDirectoryExists(localPath); - - // 下载文件到临时路径 - using (var client = new WebClient()) + try { - await client.DownloadFileTaskAsync( - new Uri($"{BaseDownloadUrl}File/{relativePath}"), - tempPath); + // 更新状态显示当前下载进度 + int current = Interlocked.Increment(ref _completedFiles); + UpdateStatus($"正在下载 ({Update_Pro.Value + 1}/{Update_Pro.Maximum}): {expectedMd5}"); + + // 下载文件到内存 + using (var client = new HttpClient()) + { + var fileUrl = $"{BaseDownloadUrl}File/{expectedMd5}"; + var response = await client.GetAsync(fileUrl); + response.EnsureSuccessStatusCode(); + + byte[] fileData = await response.Content.ReadAsByteArrayAsync(); + + // 存储到内存字典 + lock (_downloadedFiles) + { + _downloadedFiles[relativePath] = (fileData, expectedMd5); + } + } + + // 更新进度 + UpdateProgress(); + } + catch (Exception ex) + { + UpdateStatus($"下载失败: {relativePath} - {ex.Message}"); + throw; + } + } + + /// + /// 校验并保存所有已下载的文件 + /// + private void VerifyAndSaveAllFiles() + { + UpdateStatus("正在校验文件..."); + + // 创建失败文件列表 + var failedFiles = new List(); + + foreach (var item in _downloadedFiles) + { + string relativePath = item.Key; + byte[] data = item.Value.Data; + string expectedMd5 = item.Value.ExpectedMd5; + + try + { + // 计算内存中数据的MD5 + string actualMd5; + using (var md5 = MD5.Create()) + { + byte[] hashBytes = md5.ComputeHash(data); + actualMd5 = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); + } + + // 校验MD5 + if (actualMd5 != expectedMd5.ToLower()) + { + throw new Exception($"MD5校验失败 (期望: {expectedMd5}, 实际: {actualMd5})"); + } + + // 获取本地路径并创建目录 + string localPath = GetLocalPath(relativePath); + EnsureDirectoryExists(localPath); + + // 保存文件 + File.WriteAllBytes(localPath, data); + } + catch (Exception ex) + { + UpdateStatus($"文件校验失败: {relativePath} - {ex.Message}"); + failedFiles.Add(relativePath); + } } - // 验证文件MD5 - VerifyFileMd5(tempPath, expectedMd5, relativePath); - // 替换现有文件 - ReplaceExistingFile(tempPath, localPath); + // 清理失败的文件记录 + foreach (var failedFile in failedFiles) + { + _downloadedFiles.Remove(failedFile); + } + + if (failedFiles.Count > 0) + { + throw new Exception($"{failedFiles.Count}个文件校验失败"); + } } ///