OK, so I'm working on a game launcher. It checks for an update, if it exists it gets downloaded and unzipped. After unzipping is finished, new files are copied where they are needed and then the zip and the unzipped files are deleted.
The problem is this: if the user closes the launcher while unzipping, the next time they launch it, I get an error while unzipping - the file already exists.
So what I would like to do is delete the Patch folder when exiting. However, if the background worker is running, the resource cannot be deleted as it is being used by another process.
The downloader class:
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();
}
}
}
and then the 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
}
I terminate the application by calling the App.Current.Shutdown();
method.