Skip Navigation LinksHome > View Post

System.Packaging for your own files

There's been a lot of excitement about the new Office file formats that shipped with Office 2007. As I'm sure you're aware, the new .docx and .xslx (etc) files are actually zip files that contain all the resources and XML etc that makes up the new Open XML files.

The idea of using zip containers is especially powerful for a number of reasons including reduced file size and, perhaps most importantly, extensibility. Yup, if you need to add something new to your file structure then you can potentially avoid any nasty versioning issues with your Xml or binary format by simply adding a new file to the archive.

Tidy.

Best of all, support for this kind of file format (called a package) shipped with .NET 3.0 and is available for you to use with your own files (or to poke around a .docx file if thats what you need to do).

I have an application that allows you to save your work and reload it later. As always, I use the XmlSerializer to serialize my working model to disk, like so.

public void Save(MyData myData)
{
    SaveFileDialog dialog = new SaveFileDialog();
    dialog.Filter = "Josh Files (*.josh)|*.josh|All Files|*.*";
    if (dialog.ShowDialog().GetValueOrDefault())
{
    using (FileStream fs = new FileStream(dialog.FileName, FileMode.OpenOrCreate))
        {
            XmlSerializer ser = new XmlSerializer(typeof(MyData));
            ser.Serialize(fs, myData);
        }
    }
}

Easy. But what if we wanted to use the new Packaging system - don't worry, that's easy to.

// first we need to create a Uri to specify where our part goes in the package.
private static readonly Uri XML_DATA_PART_URI = PackUriHelper.CreatePartUri(new Uri("/MyData.xml", UriKind.Relative));

public void Save(MyData myData)
{
    SaveFileDialog dialog = new SaveFileDialog();
    dialog.Filter = "JoshX Files (*.joshx)|*.joshx|All Files|*.*";

    if (dialog.ShowDialog(window).GetValueOrDefault())
    
    {
        using (Package package = Package.Open(dialog.FileName, FileMode.OpenOrCreate))
        {
            PackagePart part = package.CreatePart(XML_DATA_PART_URI, "text/xml", CompressionOption.Normal);
            XmlSerializer ser = new XmlSerializer(typeof(List<TraceEvent>));
            ser.Serialize(part.GetStream(), myData);
        }
    }
}

You can even rename the file to .zip and have a poke around using Windows Explorer

MyData Package in Windows Explorer

Told you it was easy... and if I wanted to load this data later?

public MyData Load(Window window)
{
    OpenFileDialog dialog = new OpenFileDialog();
    dialog.Filter = "JoshX Files (*.joshx)|*.joshx|All Files|*.*";
    if (dialog.ShowDialog(window).GetValueOrDefault())
    {
        using (Package package = Package.Open(dialog.FileName, FileMode.Open))
        {
            PackagePart part = package.GetPart(XML_DATA_PART_URI);
            XmlSerializer ser = new XmlSerializer(typeof(MyData));
            return (MyData)ser.Deserialize(part.GetStream());
        }
    }

    // if the user cancels out - return null
    return null;
}

I should have called this post "Yes, you too can add an 'x' to the end of your file extension!".

For a much fuller article on using System.Packaging (and covering relationships which I've ignored in this example) why not check out Jack Davis and Andrey Shur's recent MSDN article: A New Standard For Packaging Your Data.

Tags: .NET

 
Josh Post By Josh Twist
2:35 AM
30 Jul 2007

» Next Post: Building Chairs out of Atoms
« Previous Post: True or False in PowerShell

Comments are closed for this post.

Posted by David Travis @ 30 Jul 2007 10:39 AM
Hi Josh,

Cool stuff as always. Just note that the link to the MSDN article is not correct.

Thanks.

Posted by Josh @ 30 Jul 2007 11:09 AM
Thanks David,

Well spotted and thanks for letting me know. All fixed now :)

Posted by Paul Cunningham @ 31 Jul 2007 1:00 AM
Neat - reminds me of the ".pak" format used in the Quake titles.

© 2005 - 2014 Josh Twist - All Rights Reserved.