/// <summary> /// 尝试把目标文件剪切到备份文件夹下,如果目标文件存在才会移动备份 /// </summary> /// <param name="localFileItem"></param> private void TryBackupOneFile(LocalFileItem localFileItem) { try { //检查创建备份文件的所在目录 FileHelper.CheckCreateParentDir(localFileItem.backupFilePath); if (File.Exists(localFileItem.targetFilePath)) { //尝试先删除备份文件 if (File.Exists(localFileItem.backupFilePath)) { File.Delete(localFileItem.backupFilePath); } //把需要备份的文件移动到备份文件夹。 File.Move(localFileItem.targetFilePath, localFileItem.backupFilePath); Log.Info($"UpdateTask.TryBackupOneFile(): 移动目标文件到备份文件夹 {localFileItem.fileItem.relativePath}"); //记录备份文件 backupFileList.Add(localFileItem); } } catch (Exception e) { Log.Error($"UpdateTask.TryBackupOneFile(): 移动目标文件{localFileItem.fileItem.relativePath}到备份文件夹时异常:" + e.Message); } }
/// <summary> /// 使用一个服务器上下下来的FolderConfig,加上本地配置LocalSetting。 /// 初始化自己的整个内容 /// </summary> /// <param name="fileItemDict"></param> public void InitWithFolderConfig(ConcurrentDictionary <string, FileItem> fileItemDict) { //先clear fileItemClientDict.Clear(); foreach (var fileItem in fileItemDict.Values) { LocalFileItem fic = new LocalFileItem(); fic.fileItem = fileItem; fic.tempFilePath = Path.Combine(localSetting.tempFolderPath, fic.fileItem.relativePath); fic.targetFilePath = Path.Combine(localSetting.targetFolderPath, fic.fileItem.relativePath); fic.backupFilePath = Path.Combine(localSetting.backupFolderPath, fic.fileItem.relativePath); fileItemClientDict.Add(fic.fileItem.relativePath, fic); } }
/// <summary> /// 把备份文件恢复到目标文件。 /// </summary> public void RecoverFile() { //先把改动过的文件移动回临时文件夹 for (int i = 0; i < hasMoveFileList.Count; i++) { LocalFileItem localFileItem = hasMoveFileList[i]; if (!File.Exists(localFileItem.targetFilePath)) { continue; } if (File.Exists(localFileItem.tempFilePath)) { File.Delete(localFileItem.tempFilePath); } //把目标文件移动到临时文件 File.Move(localFileItem.targetFilePath, localFileItem.tempFilePath); Log.Info($"UpdateTask.RecoverFile(): 把目标文件移动到临时文件 {localFileItem.fileItem.relativePath}"); } //遍历备份文件列表 for (int i = 0; i < backupFileList.Count; i++) { LocalFileItem localFileItem = backupFileList[i]; if (!File.Exists(localFileItem.backupFilePath)) { continue; } if (File.Exists(localFileItem.targetFilePath)) { File.Delete(localFileItem.targetFilePath); } //剪切备份文件到目标文件 File.Move(localFileItem.backupFilePath, localFileItem.targetFilePath); Log.Info($"UpdateTask.RecoverFile(): 把备份文件恢复到目标文件 {localFileItem.fileItem.relativePath}"); } Log.Info($"UpdateTask.RecoverFile(): 备份文件恢复到目标文件结束"); hasMoveFileList.Clear(); backupFileList.Clear(); }
/// <summary> /// 从临时文件移动到目标文件,这是一个阻塞函数。如果在主线程中可能应该异步调用执行。但是这样最后会导致事件无法回到主线程。 /// </summary> /// <returns></returns> public void MoveFile() { Log.Info($"UpdateTask.MoveFile(): 开始移动文件!!!"); //清空备份列表的记录 backupFileList.Clear(); hasMoveFileList.Clear(); try { foreach (var kv in localFolder.fileItemClientDict) { LocalFileItem localFileItem = kv.Value; //如果目标文件是否已经存在,目标文件和临时文件的md5是否一致。都不成立就备份目标文件到备份文件夹下。 if (File.Exists(localFileItem.targetFilePath) && //localFileItem.fileItem.MD5 == MD5Helper.FileMD5(localFileItem.targetFilePath))//<-----这里重新计算了一次MD5 localFileItem.fileItem.MD5 == localFileItem.lastTargetMD5) //暂时不再重新计算一次了 { Log.Info($"UpdateTask.MoveFile(): 不需要移动文件 {localFileItem.targetFilePath}"); continue; } else { //尝试把目标文件剪切到备份文件夹下,如果目标文件存在才会移动备份 if (File.Exists(localFileItem.targetFilePath)) { TryBackupOneFile(localFileItem); } } //检查创建目标文件的所在目录。 FileHelper.CheckCreateParentDir(localFileItem.targetFilePath); //从临时文件移动到目标文件 if (File.Exists(localFileItem.tempFilePath)) { Log.Info($"UpdateTask.MoveFile(): 移动临时文件到目标文件夹下-> {localFileItem.fileItem.relativePath}"); File.Move(localFileItem.tempFilePath, localFileItem.targetFilePath); hasMoveFileList.Add(localFileItem); } else { Log.Error($"UpdateTask.MoveFile(): 源路径不存在 : {localFileItem.tempFilePath}, 无法剪切。"); } } } catch (Exception e) { Log.Warning($"UpdateTask.MoveFile(): 移动文件异常 {e}"); OnException(); } //移动结束后,比对目标文件和xml的md5是否一致 if (CheckTargetFileMD5WithXML()) { Log.Info("UpdataTask.MoveFile(): 移动文件成功"); if (null != EventMoveDone) { EventMoveDone(this, true); } } else { if (null != EventError) { EventError(new Exception()); } Log.Info("UpdataTask.MoveFile(): 移动文件出错,移动后文件和服务器的不一致"); } }
/// <summary> /// 由一个FileItemTask下载一项文件的方法 /// </summary> /// <param name="localFileItem"></param> /// <returns></returns> private async Task DownLoadOneFile(LocalFileItem localFileItem) { if (!localFileItem.IsNeedDownload)//之前的MD5比对不需要下载就不下了 { return; } Log.Info("UpdateTask.DownLoadOneFile():开始下载文件项: " + localFileItem.fileItem.url); FileItem fileItem = localFileItem.fileItem; if (File.Exists(localFileItem.tempFilePath))//如果已经下过一个了 { if (MD5Helper.Compare(localFileItem.tempFilePath, localFileItem.fileItem.MD5, localFileItem.fileItem.size)) { //那么这个文件就不需要下载了 Log.Info("UpdateTask.DownLoadOneFile():存在一致的临时文件" + localFileItem.fileItem.relativePath); localFileItem.IsNeedDownload = false;//标记它不用下载了 return; } else { File.Delete(localFileItem.tempFilePath);//如果下好的临时文件MD5不一致,那么就删除这个以前的临时文件 } } //如果这个临时文件所在的上级文件夹不存在那么就创建 FileHelper.CheckCreateParentDir(localFileItem.tempFilePath); int isDone = 0; Interlocked.Exchange(ref isDone, 0); FileStream fs = null; //需要下载的文件是空文件,不用下载,本地直接创建一个空文件就行了。 if (localFileItem.fileItem.size == 0) { fs = new FileStream(localFileItem.tempFilePath, FileMode.Create); fs.Close(); return; } try { //下载文件的后缀加上.temp fs = new FileStream(localFileItem.tempFilePath + ".temp", FileMode.OpenOrCreate); Log.Info("UpdateTask.DownLoadOneFile():开始http连接..."); Http.Get(fileItem.url) .OnMake((req) => { req.AddRange(fs.Length);//设置断点续传 }) .OnSuccess((WebHeaderCollection collection, Stream stream) => { try { fs.Seek(fs.Length, SeekOrigin.Begin); CopyStream(stream, fs);//阻塞的下载?但是进入OnSuccess会是一个异步小线程 Log.Info("UpdateTask.DownLoadOneFile():下载成功!"); } catch (Exception e) { Log.Error($"UpdateTask.DownLoadOneFile.CopyStream():{fileItem.url}下载异常:" + e.Message); //EventError?.Invoke(e); //暂时不传出事件了 } fs.Close(); Interlocked.Increment(ref isDone);//下载完成 }) .OnFail((e) => { if (fs != null) { fs.Close(); } Log.Error($"UpdateTask.DownLoadOneFile.OnFail():{fileItem.url}下载异常:" + e.Message); //EventError?.Invoke(e); //暂时不传出事件了 Interlocked.Increment(ref isDone);//下载完成 }).Go(); while (true) { Log.Debug("UpdateTask.DownLoadOneFile():await Task.Delay(1)之前 当前执行线程id=" + Thread.CurrentThread.ManagedThreadId); await Task.Delay(1); Log.Debug("UpdateTask.DownLoadOneFile():await Task.Delay(1)之后 当前执行线程id=" + Thread.CurrentThread.ManagedThreadId); //await WaitDelay(); if (isDone > 0) { break; } } //下载成功后把文件名的.temp去掉 File.Move(localFileItem.tempFilePath + ".temp", localFileItem.tempFilePath); } catch (Exception e) { Log.Error("UpdateTask.DownLoadOneFile():下载异常:" + e.Message); if (fs != null) { fs.Close(); } } }