Home > Posts > HowTo: Write directly into a ZIP stream using DotNetZip

HowTo: Write directly into a ZIP stream using DotNetZip

At ClipFlair’s Playground Silverlight app I’m using DotNetZip library (Ionic.Zip namespace) for writing saved component state to a .ZIP file. In fact the Activity container there can create one .ZIP for each state that contains one .ZIP per-component it hosts (it can even host multiple instances of its own Activity component type to have nested Activities in its ZUI interface).

DotNetZip is a perfect match for Silverlight’s security restrictions, where OpenFileDialog and SaveFileDialog only give you a stream to work with (unless your app has been granted elevated trust), since apart from working with filesystem files and folders it allows you to also give it content to compress in the form of a stream.

Note: the latest DotNetZip 1.9.1.8 official version for Silverlight doesn’t work correctly – you need a patched build, see: https://zoomicon.wordpress.com/2012/11/25/howto-use-dotnetzip-ionic-zip-library-in-silverlight/

For working with streams at DotNetZip there are two options (as explained at http://dotnetzip.codeplex.com/discussions/231712):

1) pass it an in-memory buffer (this is a non-optimal method)

public override void SaveOptions(ZipFile zip, string zipFolder = "")  
{
base.SaveOptions(zip, zipFolder);
MemoryStream
stream = new MemoryStream(); //non-optimal, uses memory buffer
gridCaptions.WriteCaptions(stream, "captions.srt"); stream.Position = 0;
zip.AddEntry(zipFolder + "/captions.srt", stream);
}

2) the other is to pass it a write delegate for a method that writes the data to a stream that DotNetZip will pass to it when needed.

public override void SaveOptions(ZipFile zip, string zipFolder = "")
{
  base.SaveOptions(zip, zipFolder);
  zip.AddEntry(zipFolder + "/captions.srt", SaveCaptions);
}

public void SaveCaptions(string entryName, Stream stream)
{
  gridCaptions.WriteCaptions(stream, entryName);
}

 

In case one needs to pass more parameters (apart from the zip entry name and the stream that DotNetZip passes to the delegate), they could instantiate a class instance and keep the parameter there, then pass a method of that class via the delegate to DotNetZip. An easier way is to use an anonymous method and define it in a context where the parameter is available, e.g. as a local variable.

public override void SaveOptions(ZipFile zip, string zipFolder = "")
{
  base.SaveOptions(zip, zipFolder);
  foreach (BaseWindow window in activity.Windows)
    SaveWindow(zip, zipFolder, window);
}

private static void SaveWindow(ZipFile zip, string zipFolder, BaseWindow window)
{
  string title = ((string)window.Title).TrimStart(); 
//using TrimStart() to not have filenames start with
//space chars in case it's an issue with ZIP spec
if (title == "") title = window.GetType().Name; zip.AddEntry( zipFolder + "/" + title + " - " + Guid.NewGuid() + ".clipflair.zip", new WriteDelegate((entryName, stream) => { window.SaveOptions(stream); }) );
//save ZIP file for child window }
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: