2015-03-31 57 views
0

好吧,我正在开发一款游戏启动器。它会检查更新,如果存在,它会被下载并解压缩。解压缩完成后,将在需要的位置复制新文件,然后删除压缩文件和解压缩的文件。用于后台工作者的发布资源c#WPF

问题是这样的:如果用户在解压缩时关闭启动器,下次启动时,解压缩时出现错误 - 文件已存在。

所以我想要做的是在退出时删除Patch文件夹。但是,如果后台工作正在运行,则该资源不能被删除,因为它正在被另一个进程使用。

下载器类:

static void downloader_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = sender as BackgroundWorker; 

     if (!Directory.Exists(Path.Combine(BASE_DIR, "Patch"))) 
      Directory.CreateDirectory(Path.Combine(BASE_DIR, "Patch")); 

     string sFilePathToWriteFileTo = Path.Combine(BASE_DIR, "Patch", "patch.zip").ToString(); 

     // first, we need to get the exact size (in bytes) of the file we are downloading 
     Uri url = new Uri(sUrlToReadFileFrom); 
     System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); 
     System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse(); 
     response.Close(); 
     // gets the size of the file in bytes 
     Int64 iSize = response.ContentLength; 

     // keeps track of the total bytes downloaded so we can update the progress bar 
     Int64 iRunningByteTotal = 0; 

     // use the webclient object to download the file 
     using (System.Net.WebClient client = new System.Net.WebClient()) 
     { 
      // open the file at the remote URL for reading 
      using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom))) 
      { 
       // using the FileStream object, we can write the downloaded bytes to the file system 
       using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None)) 
       { 
        // loop the stream and get the file into the byte buffer 
        int iByteSize = 0; 
        byte[] byteBuffer = new byte[1024]; 
        double dTotal = (double)iSize; 
        while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0) 
        { 
         // write the bytes to the file system at the file path specified 
         streamLocal.Write(byteBuffer, 0, iByteSize); 
         iRunningByteTotal += iByteSize; 

         // calculate the progress out of a base "100" 
         double dIndex = (double)(iRunningByteTotal); 
         double dProgressPercentage = (dIndex/dTotal); 
         int iProgressPercentage = (int)(dProgressPercentage * 100); 

         // update the progress bar 
         worker.ReportProgress(iProgressPercentage); 
        } 

        // clean up the file stream 
        streamLocal.Close(); 
       } 
       // close the connection to the remote server 
       streamRemote.Close(); 
      } 
     } 

    } 

然后unzipper:

private void decompresser_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = sender as BackgroundWorker; 
     #region Unzip files 

     if (!Directory.Exists(decompressPath)) 
      Directory.CreateDirectory(decompressPath); 

     using (ZipArchive archive = ZipFile.OpenRead(archiveName)) 
     { 
      int iTotal = archive.Entries.Count(); 
      int curr = 0; 
      foreach (ZipArchiveEntry entry in archive.Entries) 
      { 
       if (entry.FullName != entry.Name) 
       { 
        if (entry.Name == string.Empty) 
        { 
         //create folder here 
         Directory.CreateDirectory(Path.Combine(decompressPath, entry.FullName)); 
        } 
        else 
        { 
         //create folder and extract file into it 
         string dirToCreate = entry.FullName.Replace(entry.Name, ""); 
         Directory.CreateDirectory(Path.Combine(decompressPath, dirToCreate)); 
         entry.ExtractToFile(Path.Combine(decompressPath, entry.FullName)); 
        } 
       } 
       else 
       { 
        //just extract file 
        Console.WriteLine(Path.Combine(decompressPath, entry.FullName)); 
        entry.ExtractToFile(Path.Combine(decompressPath, entry.FullName)); 
       } 

       curr++; 
       var progress = ((double)curr/(double)iTotal) * 60.0; 
       worker.ReportProgress((int)progress); 
      } 
     } 

     //delete zip file 
     File.Delete(Path.Combine(BASE_DIR, "Patch", "patch.zip")); 
     #endregion 

     #region Copy files 
     string sourceDirName = Path.Combine(BASE_DIR, "Patch"); 
     string destDirName = BASE_DIR; 
     DirectoryInfo dir = new DirectoryInfo(sourceDirName); 
     long maxbytes = 0; 
     List<FileInfo> files = new List<FileInfo>(); 
     FileInfo[] folder = dir.GetFiles("*.*", SearchOption.AllDirectories); 
     foreach (FileInfo file in folder) 
     { 
      if ((file.Attributes & FileAttributes.Directory) != 0) continue; 
      files.Add(file); 
      maxbytes += file.Length; 
     } 

     // Copy files 
     long bytes = 0; 
     foreach (FileInfo file in files) 
     { 
      try 
      { 
       //where to copy 
       string copyPath = file.FullName.Replace("Patch\\", "").Replace(file.Name, ""); 
       if (!Directory.Exists(copyPath)) 
        Directory.CreateDirectory(copyPath); 
       File.Copy(file.FullName, Path.Combine(copyPath, file.Name), true); 
       var progress = 60 + ((double)bytes/(double)maxbytes) * 30.0; 
       worker.ReportProgress((int)progress); 
      } 
      catch (Exception ex) 
      { 
      } 
      bytes += file.Length; 
     } 

     #endregion 

     #region Clean Up 

     foreach (FileInfo file in files) 
     { 
      try 
      { 
       var progress = 90 + ((double)(maxbytes - file.Length)/(double)maxbytes) * 9; 

       file.Delete(); 
       worker.ReportProgress((int)progress); 
      } 
      catch (Exception ex) { } 
     } 
     try 
     { 
      string delPath = Path.Combine(BASE_DIR, "Patch"); 
      Directory.Delete(delPath, true); 
     } 
     catch (Exception ex) { } 

     worker.ReportProgress(100); 


     #endregion 
    } 

我通过调用App.Current.Shutdown();方法终止应用程序。

回答

0

如果我没有遗漏任何东西,那么有一个非常简单的解决方案。 您可以使用退出时的应用程序event通过调用workerObject.RequestStop();来停止所有后台工作人员(注意,它仅向工人中的代码发出已发出停止请求的信号,您需要在工作人员的工作循环中处理此事以停止工作)。然后你可以清理补丁文件夹。

0

为了避免这个问题,您是否也可以在启动应用程序时删除修补程序文件夹,但在开始下载之前?

0

@GWLlosa - 我没想到一经推出删除文件,如果需要的话,但我要的是保存作为最后的手段,如果我不能找到更好的东西

我想是这样的

protected override void OnClosing(System.ComponentModel.CancelEventArgs e) 
     { 
      updater.CancelAsync(); 
      while (updater.IsBusy) 
      { 
       Thread.Sleep(100); 
      } 
//run code to delete the files after the worked has stopped 
} 

但这只能让我无限循环:)

0

如果我这样做,我会找到并杀死立即发射后下载过程。

Process[] p = Process.GetProcessesByName("processname"); 
foreach (var proc in p) 
{ 
    proc.Kill(); 
} 
0

我有2个解决方案为您的问题。

1)不要试图在退出时删除补丁文件夹,只需启动&忘记BackgroundWorker,如果用户取消补丁并退出,则退出应用程序。但是在用户启动应用程序时,特别是在您调用解压缩之前,请务必删除修补程序文件夹。 2)如果您仍想删除退出时的补丁文件夹,请使用CancelAsync()函数取消您的BackgroundWorker。例如

private void btnStart_Click(object sender, EventArgs e) 
{ 
    if (btnStart.Text == "Start") 
    { 
     ... 
    } 
    else 
    { 
     m_bgWorker.CancelAsync(); 
    } 
} 


private void SearchFiles(string strPath, string strPattern) 
{ 
    string strMessage = "Parsing directory " + strPath; 
    m_bgWorker.ReportProgress(0, strMessage); 
    foreach (string strFileName in Directory.GetFiles(strPath, strPattern)) 
    { 
     if (m_bgWorker.CancellationPending) 
     { 
      return; 
     } 
     else 
     { 
      m_lstFiles.Add(strFileName); 
     } 
    } 

    foreach (string strDirName in Directory.GetDirectories(strPath)) 
    { 
     if (m_bgWorker.CancellationPending) 
     { 
      return; 
     } 
     else 
     { 
      SearchFiles(strDirName, strPattern); 
     } 
    } 
} 

我得到了代码表格post。您可以从该示例中阅读更多内容,以了解作者如何取消他的BackgroundWorker。

+0

我之前写了一条评论,解释说我已经试过了:)我捕获了关机事件,停止了它,试图取消同步,但没有工作。据我所知,问题在于使用块,因为它们在操作完成之前不会释放它们的资源。 – m0rgul 2015-04-01 08:41:42

+0

如何将CancelAsync()转发给您的解压缩器BackgroundWorker?如果使用block会导致问题,那很奇怪。因为如果您使用CancelAsync()解压缩操作,则使用块(ZipArchive archive = ZipFile.OpenRead(archiveName))现在超出范围,因此ZipArchive对象也应该处置并且所有解压缩过程也应该终止。 – 2015-04-01 09:25:55

+0

显然这不会发生。我实际上在这里和那里使用了一些console.writeline,显然,在“使用”块内,不会收到工作者取消事件。所以我的猜测是这个块创建了某种“单独的环境”,因此在此范围之外更改变量不会影响使用块。所以,一段时间以来,我的头反对这个问题,我决定去一个更容易... ...开始删除文件:) – m0rgul 2015-04-06 08:49:24