refactor(下载逻辑): 重构文件下载和校验流程
将文件下载和校验逻辑拆分为独立的方法,引入内存缓存机制,避免频繁的磁盘操作。所有文件下载完成后统一校验和保存,提高代码可维护性和执行效率。
This commit is contained in:
parent
5ec395740f
commit
2a339142ad
132
Form1.cs
132
Form1.cs
@ -33,6 +33,9 @@ namespace CheckDownload
|
||||
|
||||
/// <summary>在线MD5文件名,从DNS查询获取</summary>
|
||||
private string _onlineMd5File = "";
|
||||
|
||||
// 类级别变量,用于存储下载的文件数据
|
||||
private Dictionary<string, (byte[] Data, string ExpectedMd5)> _downloadedFiles = new Dictionary<string, (byte[], string)>();
|
||||
/// <summary>已完成下载的文件数</summary>
|
||||
private int _completedFiles = 0;
|
||||
|
||||
@ -345,7 +348,9 @@ namespace CheckDownload
|
||||
/// <returns>下载任务</returns>
|
||||
private async Task DownloadUpdatedFiles(Dictionary<string, string> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -371,56 +379,110 @@ namespace CheckDownload
|
||||
/// <returns>下载任务</returns>
|
||||
private async Task DownloadFileWithSemaphore(KeyValuePair<string, string> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载并验证文件
|
||||
/// 下载文件到内存并暂存
|
||||
/// </summary>
|
||||
/// <param name="relativePath">文件的相对路径</param>
|
||||
/// <param name="expectedMd5">期望的MD5值</param>
|
||||
/// <returns>下载任务</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验并保存所有已下载的文件
|
||||
/// </summary>
|
||||
private void VerifyAndSaveAllFiles()
|
||||
{
|
||||
UpdateStatus("正在校验文件...");
|
||||
|
||||
// 创建失败文件列表
|
||||
var failedFiles = new List<string>();
|
||||
|
||||
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}个文件校验失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
x
Reference in New Issue
Block a user