Share via


Unzipping files with a progress bar in Windows Store applications (XAML/C#)

Here’s a method for unzipping a Zip file in a Windows Store application. ZipArchive is part of System.IO.Compression.

 private async Task UnzipWithProgress(StorageFolder outFolder, Stream zipFileStream, ProgressBar pb)
{
    bool bDelete = false;

    using (var archive = new ZipArchive(zipFileStream))
    {
        try
        {
            // Ensure the UI update part runs in the UI thread
            var ignore = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                this.tbDownloadStatus.Text = "Unzipping";
                pb.Value = 0;
                pb.Maximum = archive.Entries.Count;
            });

            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                if (entry.Name != "")
                {
                    string fileName = entry.FullName.Replace("/", @"\");
                    StorageFile newFile = await CreateFile(outFolder, fileName);
                    Stream newFileStream = await newFile.OpenStreamForWriteAsync();
                    Stream fileData = entry.Open();
                    byte[] data = new byte[entry.Length];
                    int len = await fileData.ReadAsync(data, 0, data.Length);
                    while (len > 0)
                    {
                        await newFileStream.WriteAsync(data, 0, len);
                        len = await fileData.ReadAsync(data, 0, data.Length);
                    }
                    await newFileStream.FlushAsync();

                    var ignore2 = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        pb.Value++;
                    });
                }
            }

            var itemId = OriginalUriString;
            this.Frame.Navigate(typeof(ItemDetailPage), itemId);
        }
        catch (Exception ex)
        {
            bDelete = true;
        }
        finally
        {
            if (bDelete)
                outFolder.DeleteAsync();
        }
    }
}

To use it, call it this way. In my case I called it from the LoadState method.

 StorageFile file;
try
{
    file = await ApplicationData.Current.LocalFolder.GetFileAsync(OriginalUriString);
}
catch (FileNotFoundException)
{
    file = null;
}

if (file != null)
{
    using (var ws = await file.OpenReadAsync())
    using (var forReadRandomStream = ws.AsStreamForRead(0))
    {
        string path = ApplicationData.Current.LocalFolder.Path + @"\" + Path.GetFileNameWithoutExtension(file.Name) + @"\";
        await UnzipWithProgress(await StorageFolder.GetFolderFromPathAsync(path), forReadRandomStream, progressBar1);
    }
}

Apologize that this is not a File->New demo, but I thought it might be useful and Scott Hanselman made me do it.