Saturday, December 05, 2009

Library of the Week: SharpZipLib with Silverlight

{

SharpZipLib has been around in various forms for some time but via this port to Silverlight we have the benefit of leveraging it for compression and decompression in our Silverlight based web applications. Doing a search on sample code gives back a lot of examples (the best of which, IMHO, is from The Codecruncher) of how to use the library but there’s an important difference when it’s used in the Silverlight space: many members of the FileStream are marked as SECURITY CRITICAL and are therefore out of reach in your application. A very simple technique to get around this is to convert the target stream object to a MemoryStream and proceed from there. A series of examples are below, written in simpe form for brevity (reading a file in a single step to a large byte array is a taste thing; of course I’m aware you can read chunks of the file) Here’s a little sample of getting that done:

public MemoryStream GetFileData(FileStream fs) 
{
fs.Seek(0, SeekOrigin.Begin);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, (int)fs.Length);
MemoryStream ms = new MemoryStream(data);
return ms;
}




Here are examples of listing, extracting, and compressing files, respectively:






//open a file dialog, pick a zip and list contents
List entries = new List();
OpenFileDialog ofd = new OpenFileDialog();
if (true == ofd.ShowDialog())
{

using(FileStream fs = ofd.File.OpenRead())
{
ZipFile zip = new ZipFile(GetFileData(fs));
foreach (ZipEntry entry in zip)
{
entries.Add(entry.Name);
}
zipFileListBox.ItemsSource = entries.ToArray();
}








//open a file dialog, pick a *.zip and extract to isolated storage
OpenFileDialog ofd = new OpenFileDialog();
if (true == ofd.ShowDialog())
{
string fiName = ofd.File.Name;
ZipEntry entry;
using(ZipInputStream zis = new ZipInputStream(GetFileData(ofd.File.OpenRead())))
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
string folderForOutput = System.IO.Path.GetFileNameWithoutExtension(ofd.File.Name);
if (!isf.DirectoryExists(folderForOutput)) {
isf.CreateDirectory(folderForOutput);
}

while ((entry = zis.GetNextEntry()) != null)
{
if (isf.FileExists(entry.Name))
{
isf.DeleteFile(entry.Name);
}
long sizeToWrite = entry.Size;
using (FileStream fs = isf.CreateFile(folderForOutput + "/" + entry.Name))
using(StreamWriter sw = new StreamWriter(fs))
{
byte[] data = new byte[sizeToWrite];
int bytesRead = zis.Read(data, 0, data.Length);
if (bytesRead > 0)
{
sw.Write(data);
}
}
}
}
}








//open a file dialog, pick some files and create a *.zip
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = true;
if (true == ofd.ShowDialog())
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (FileStream fs = isf.CreateFile("TheZip.zip"))
using (ZipOutputStream zipOut = new ZipOutputStream(fs))
{
foreach (FileInfo selectedFile in ofd.Files) {
byte[] fileData = new byte[selectedFile.Length];
using (FileStream selectedFileStream = selectedFile.OpenRead()) {
selectedFileStream.Read(fileData, 0, fileData.Length);
ZipEntry entry = new ZipEntry(selectedFile.Name);
entry.DateTime = DateTime.Now;
entry.Size = selectedFile.Length;
zipOut.PutNextEntry(entry);
zipOut.Write(fileData, 0, fileData.Length);
}
}
zipOut.Finish();
}
}
}




It must be noted that SharpZipLib is GPL but because of a special clause in the license, you can use it in a “closed source” application as Jon Galloway explains here.



}