好吧,我正在开发一款游戏启动器。它会检查更新,如果存在,它会被下载并解压缩。解压缩完成后,将在需要的位置复制新文件,然后删除压缩文件和解压缩的文件。用于后台工作者的发布资源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();
方法终止应用程序。
我之前写了一条评论,解释说我已经试过了:)我捕获了关机事件,停止了它,试图取消同步,但没有工作。据我所知,问题在于使用块,因为它们在操作完成之前不会释放它们的资源。 – m0rgul 2015-04-01 08:41:42
如何将CancelAsync()转发给您的解压缩器BackgroundWorker?如果使用block会导致问题,那很奇怪。因为如果您使用CancelAsync()解压缩操作,则使用块(ZipArchive archive = ZipFile.OpenRead(archiveName))现在超出范围,因此ZipArchive对象也应该处置并且所有解压缩过程也应该终止。 – 2015-04-01 09:25:55
显然这不会发生。我实际上在这里和那里使用了一些console.writeline,显然,在“使用”块内,不会收到工作者取消事件。所以我的猜测是这个块创建了某种“单独的环境”,因此在此范围之外更改变量不会影响使用块。所以,一段时间以来,我的头反对这个问题,我决定去一个更容易... ...开始删除文件:) – m0rgul 2015-04-06 08:49:24