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.
FolderPicker saveFolder = new FolderPicker();
saveFolder.SuggestedStartLocation = PickerLocationId.Desktop;
saveFolder.FileTypeFilter.Add("*");
StorageFolder storageFolderForCompression = await saveFolder.PickSingleFolderAsync();
Step 2
Retrieve the files present under the selected folder:
IReadOnlyList<StorageFile> filesToCompress = await
GetStorageFiles(storageFolderForCompression as IStorageItem);
Helper Methods
async Task<List<StorageFile>> GetStorageFiles(IStorageItem storageItem)
{
List<StorageFile> storageFileList = new List<StorageFile>();
IReadOnlyList<IStorageItem> items = await (storageItem as StorageFolder).GetItemsAsync();
foreach(IStorageItem item in items)
{
switch(item.Attributes)
{
case FileAttributes.Directory:
List<StorageFile> temp = await GetStorageFiles(item);
Copy(temp, storageFileList);
break;
default:
storageFileList.Add(item as StorageFile);
break;
}
}
return storageFileList;
}
private void Copy(List<StorageFile> source, List<StorageFile> destination)
{
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.
FileOpenPicker fileOpenPicker = new FileOpenPicker();
fileOpenPicker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
fileOpenPicker.FileTypeFilter.Add("*");
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.
IReadOnlyList<StorageFile> filesToCompress =
await GetStorageFiles(storageFolderForCompression as IStorageItem);
StorageFile zipFile = await storageFolderForCompression.CreateFileAsync("Compressed.zip");
using (MemoryStream zipMemoryStream = new MemoryStream())
{
using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Create))
{
foreach (StorageFile fileToCompress in filesToCompress)
{
byte[] buffer = WindowsRuntimeBufferExtensions.ToArray(await FileIO.ReadBufferAsync(fileToCompress));
ZipArchiveEntry entry = zipArchive.CreateEntry(fileToCompress.Name);
using (Stream entryStream = entry.Open())
{
await entryStream.WriteAsync(buffer, 0, buffer.Length);
}
}
}
using (IRandomAccessStream zipStream = await zipFile.OpenAsync(FileAccessMode.ReadWrite))
{
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