释放后台工作程序c#WPF上使用的资源

时间:2015-03-31 12:59:38

标签: c# .net wpf

好的,所以我正在开发游戏发射器。它会检查更新,如果存在,则会下载并解压缩。解压缩完成后,将新文件复制到需要的位置,然后删除zip和解压缩的文件。

问题在于:如果用户在解压缩时关闭启动器,则下次启动它时,解压时会出错 - 文件已经存在。

所以我想要做的是退出时删除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();
            }
        }

    }

然后是解压缩器:

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();方法终止应用程序。

5 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

作为对此问题的回避,您是否还可以在启动应用程序时删除补丁文件夹,但在开始下载之前?

答案 2 :(得分: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
}

但这只会让我陷入无限循环:)

答案 3 :(得分:0)

如果我这样做,我会在启动后立即查找并终止下载过程。

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

答案 4 :(得分:0)

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

1)不要试图在退出时删除补丁文件夹,只需要激活&amp;忘记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。