10101010101001

0101010101001

Archive for March 2011

Creating a zip file with a folder in Silverlight

with 4 comments

If you happen to have a silverlight application that sends/receives files from the server side it’s a good idea to have those files compressed
Unless the files are already in some compressed format like (png, jpg, etc), this will reduce the amount of data sent through the network minimizing transfer times considerably.
So for textual file formats like xml, txt, etc I definitely recommend zipping them.
For zipping in silverlight I found two options at the time of this writing:
1) Use the System.IO.Compression.GZipStream
2) Use the SharpZipLib ported to Silverlight library.

I wouldn’t recommend the first option but for the simplest scenarios like: zip one file to one one compressed file.
If you need to create a zip archive that can contain multiple files & folders which are taken from the file-system or from in-memory content then I recommend the second option.
The only problem I had using option 2 is that documentation for sharpziplib is scarce, but persistent google searching does help.

So let’s take an example scenario and see how it’s done using SharpZipLib in Silverlight.
Suppose you have an in-memory xml, stored as a string, and the end result you want to achieve is an archive called test.zip which contains a single folder called Test.
Inside the folder you want to have the in-memory xml stored into an xml file called test.xml.
To see the end result easily we’ll write the archive to isolated storage.

So here goes the source code for the method that will do the creation of the archive:

        public byte[] GetCompressedByteArray(string content)
        {
            byte[] compressedResult;
            using (MemoryStream zippedMemoryStream = new MemoryStream())
            {
                using (ZipOutputStream zipOutputStream = new ZipOutputStream(zippedMemoryStream))
                {
                    // Highest compression rating
                    zipOutputStream.SetLevel(9);

                    byte[] buffer;

                    // The string to use as file content
                    using (MemoryStream file = new MemoryStream(Encoding.UTF8.GetBytes(content)))
                    {
                        buffer = new byte[file.Length];
                        file.Read(buffer, 0, buffer.Length);
                    }

                    // Write the data to the ZIP file            
                    ZipEntry entry = new ZipEntry("test/test.xml");
                    zipOutputStream.PutNextEntry(entry);
                    zipOutputStream.Write(buffer, 0, buffer.Length);

                    zipOutputStream.Finish();
                }

                compressedResult = zippedMemoryStream.ToArray();
            }

In the code above you can see how easily it is to create a virtual folder with a file in in a zip archive: ZipEntry entry = new ZipEntry(“test/test.xml”);.
Don’t be mislead though, although winrar and winzip will show you folders inside your zip archive, if you copy the archive to a mac/linux/android device you’ll still see only a file called “test/test.xml” since there the “/” doesn’t mean anything.
I haven’t had time to investigate this further but there’s some class ZipEntryFactory zef = new ZipEntryFactory().MakeDirectoryEntry(); which I think should be used for making directory entries.

So this GetCompressedByteArray method will return us a compressed byte array.
All we need to do now is to write it to isolated storage:

        public void WriteToIsolatedStorage(byte[] compressedBytes)
        {
            IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();
            using (IsolatedStorageFileStream zipTemplateStream = new IsolatedStorageFileStream("test.zip", FileMode.OpenOrCreate, isoStore))
            using (BinaryWriter streamWriter = new BinaryWriter(zipTemplateStream))
            {
                streamWriter.Write(compressedBytes);
            }

        }

And write some test code:

          var xmlString =
@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?>
<book>
	<version>1</version>
	<language>english</language> 	
	<chapters>
       <chapter name=""chapter1"" />
       <chapter name=""chapter2"" >
    </chapters>
</book>";
            byte[] compressedXmlStringBytes = GetCompressedByteArray(xmlString);
            WriteToIsolatedStorage(compressedXmlStringBytes);

After running it, you should get a “test.zip” inside the isolated storage.
On Windows 7 the isolated storage is located at: c:\Users\username\AppData\LocalLow\Microsoft\Silverlight\.
Just search for a file named “test.zip”, inside the folders and subfolders at that location.

If you want to see the full actual, without searching for it, the only way is to use the visual studio debugger:
Put a breakpoint on using (BinaryWriter streamWriter = new BinaryWriter(zipTemplateStream)), then move the mouse over zipTemplateStream, non-public members, and look at m_FullPath, like in the image below:
See Image

Also see here the attached VS2010 solution.

For the unzipping part you can take a look at the Unpack a zip with full control over the operation

Happy zipping :)

Advertisements

Written by Liviu Trifoi

March 22, 2011 at 12:09 pm

Posted in Silverlight

Tagged with , , , ,