How to Compress Files in Metro Style Applications






4.67/5 (2 votes)
How to use the ZipArchive class in a Metro style app to compress a set of files and save the compressed file to a particular location.
In this blog post, I am going to demonstrate how to use ZipArchive
class in Metro style app to compress a set of files and save the compressed file to a particular location.
Steps to Compress a Set of Files
Step 1
Select the folder containing the files which you want to compress.
//Select Folder to Compress
FolderPicker saveFolder = new FolderPicker();
//Suggest start location
saveFolder.SuggestedStartLocation = PickerLocationId.Desktop;
//Add file type filter
saveFolder.FileTypeFilter.Add("*");
//Opens folder picker to allow the user to select the folder to compress
StorageFolder storageFolderForCompression = await saveFolder.PickSingleFolderAsync();
Step 2
Retrieve the files present under the selected folder:
// Retrieve the files to compress
IReadOnlyList<StorageFile> filesToCompress = await
GetStorageFiles(storageFolderForCompression as IStorageItem);
Helper Methods
async Task<List<StorageFile>> GetStorageFiles(IStorageItem storageItem)
{
List<StorageFile> storageFileList = new List<StorageFile>();
// Gets the items under the selected folder (Storage Item)
IReadOnlyList<IStorageItem> items = await (storageItem as StorageFolder).GetItemsAsync();
foreach(IStorageItem item in items)
{
switch(item.Attributes)
{
case FileAttributes.Directory:
// If the item is a directory under the selected folder,
// then retrieve the files under the directory by calling the same function recursively
List<StorageFile> temp = await GetStorageFiles(item);
// Copy the files under the directory to the storage file list
Copy(temp, storageFileList);
break;
default:
// If the item is a file, Add the item to the storage file list
storageFileList.Add(item as StorageFile);
break;
}
}
// Return storage file list for compression
return storageFileList;
}
private void Copy(List<StorageFile> source, List<StorageFile> destination)
{
// For each file item present under the directory copy it to the destination storage file list
foreach (StorageFile file in source)
{
destination.Add(file);
}
}
Note: Alternatively, you can use FileOpenPicker
control’s PickMultipleFilesAsync()
method to allow the users to select multiple files instead of selecting the folder. In this way, you can skip both Step 1 and Step 2.
// File open picker
FileOpenPicker fileOpenPicker = new FileOpenPicker();
fileOpenPicker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
fileOpenPicker.FileTypeFilter.Add("*");
// Allows user to select multiple files which returns storage file list
IReadOnlyList<StorageFile> filesToCompress = await fileOpenPicker.PickMultipleFilesAsync();
Step 3
Create ZipArchive
object using a memory stream and then for each file to be compressed, add a ZipArchiveEntry
with the file name and copy the file contents to the ZipArchiveEntrystream
. Once the files are added to the zip archive, close the zip archive object and copy the contents of memory stream to the storage file which is saved to a particular location.
// Retrieve files to compress
IReadOnlyList<StorageFile> filesToCompress =
await GetStorageFiles(storageFolderForCompression as IStorageItem);
// Created new file to store compressed files
//This will create a file under the selected folder in the name “Compressed.zip”
StorageFile zipFile = await storageFolderForCompression.CreateFileAsync("Compressed.zip");
// Create stream to compress files in memory (ZipArchive can't stream to an IRandomAccessStream, see
// http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/62541424-ba7d-43d3-9585-1fe53dc7d9e2
// for details on this issue)
using (MemoryStream zipMemoryStream = new MemoryStream())
{
// Create zip archive
using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Create))
{
// For each file to compress...
foreach (StorageFile fileToCompress in filesToCompress)
{
//Read the contents of the file
byte[] buffer = WindowsRuntimeBufferExtensions.ToArray(await FileIO.ReadBufferAsync(fileToCompress));
// Create a zip archive entry
ZipArchiveEntry entry = zipArchive.CreateEntry(fileToCompress.Name);
// And write the contents to it
using (Stream entryStream = entry.Open())
{
await entryStream.WriteAsync(buffer, 0, buffer.Length);
}
}
}
using (IRandomAccessStream zipStream = await zipFile.OpenAsync(FileAccessMode.ReadWrite))
{
// Write compressed data from memory to file
using (Stream outstream = zipStream.AsStreamForWrite())
{
byte[] buffer = zipMemoryStream.ToArray();
outstream.Write(buffer, 0, buffer.Length);
outstream.Flush();
}
}
}
Thus the files under the selected folder are compressed to a particular location.
References
- http://msdn.microsoft.com/en-us/library/windows/apps/br207928.aspx
- http://msdn.microsoft.com/library/windows/apps/BR207847
- http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.pickers.folderpicker.aspx
- http://msdn.microsoft.com/en-us/library/windows/apps/system.runtime.interopservices.windowsruntime.windowsruntimebufferextensions%28v=vs.110%29.aspx
- http://msdn.microsoft.com/en-us/library/windows/apps/hh454050%28v=vs.110%29.aspx
- http://msdn.microsoft.com/en-us/library/windows/apps/system.io.compression.ziparchive%28v=vs.110%29.aspx