Click here to Skip to main content
Click here to Skip to main content

C# Use Zip Archives without External Libraries

By , 12 Jun 2011
 

Introduction

I found a lot of articles on how to access Zip archives in C# but all with significant disadvantages. The main problem is that Microsoft has Zip archives implemented in the operating system but there is no official API that we can use. In C# for example, we have the System.IO.Compression.GZip but there is no adequate System.IO.Compression.Zip class.

There are some free .NET compression libraries like SharpZipLib and .NET Zip Library, but this leads to additional installation effort and licensing problems.

It is also possible to use the free J# Library. J# has included Zip to keep compatible with the Java libraries. But to bundle a 3.6 MB DLL vjslib.dll, just to support Zip, seems like a really goofy hack.

Since .NET 3.0, we can use the System.IO.Packaging ZipPackage class in WindowsBase.DLL. It's just 1.1 MB, and it just seems to fit a lot better than importing Java libraries.

Problem only that the ZipPackage class isn't a generic Zip implementation, it's a packaging library for formats like XPS and Office Open XML that happen to use Zip.

To access simple Zip archives with ZipPackage fails because the content is checked for Package conventions.

For example, there has to be a file [Content_Types].xml in the root and only files with specified extensions are accessible. Filenames with special characters and spaces are not allowed and the access time is not the best because of the additional Package link logic.

However, the assembly WindowsBase.DLL is preinstalled and the generic Zip implementation is inside. The only problem is that the generic Zip classes are not public and visible for the programmers. But there is a simple way to get access to this hidden API and I wrote a small wrapper class for this.

Background

A quick check in the Object Browser shows us that WindowsBase.DLL has a namespace MS.Internal.IO.Zip. This sounds good, but there are no public classes visible.

However, the following call:

var types = typeof(System.IO.Packaging.Package).Assembly.GetTypes();

gives us 824 class types, public and non-public and especially one with the name MS.Internal.IO.Zip.ZipArchive. Now it is easy to get this special class type and the methods and properties:

var type = typeof(System.IO.Packaging.Package).Assembly.GetType
		("MS.Internal.IO.Zip.ZipArchive");
var static_methodes = type.GetMethods(BindingFlags.Static | 
		BindingFlags.Public | BindingFlags.NonPublic);
var nostatic_methodes = type.GetMethods(BindingFlags.Instance | 
		BindingFlags.Public | BindingFlags.NonPublic);

and we get the most important methods:

static ZipArchive OpenOnFile(string path, FileMode mode, 
	FileAccess access, FileShare share, bool streaming);
static ZipArchive OpenOnStream(Stream stream, FileMode mode, 
	FileAccess access, bool streaming);
ZipFileInfo AddFile(string path, 
	CompressionMethodEnum compmeth, DeflateOptionEnum option);
ZipFileInfo GetFile(string name);
ZipFileInfo DeleteFile(string name);
ZipFileInfoCollection GetFiles();
void Dispose();

The same procedure for ZipFileInfo and we get:

Stream GetStream(FileMode mode, FileAccess access);

and properties like: Name, LastModFileDateTime, FolderFlag...
This is all what we need to implement a small wrapper class and access over Reflection:

class ZipArchive : IDisposable
{
  private object external;
  public static ZipArchive OpenOnFile
      (string path, FileMode mode, FileAccess access, FileShare share, bool streaming)    
  {
    var type = typeof(System.IO.Packaging.Package).Assembly.GetType
		("MS.Internal.IO.Zip.ZipArchive");
    var meth = type.GetMethod("OpenOnFile", BindingFlags.Static | 
		BindingFlags.Public | BindingFlags.NonPublic);
    return new ZipArchive { external = meth.Invoke(null, new object[] 
		{ path, mode, access, share, streaming }) };
  } 
  //...
  public class ZipFileInfo //...
}

The complete ZipArchive wrapper implementation is in the demo project ZipArchiveTest in Program.cs.
Only 97 lines for this class and we can use it in a code sequence like this:

var str = new MemoryStream();

//create some files:
using (var arc = ZipArchive.OpenOnStream(str))
{
  var doc1 = new XDocument(new XElement
	("root", new XElement("item"), new XElement("item"), new XElement("item")));
  var doc2 = new XDocument(new XElement("root", Enumerable.Repeat
		("item", 1000).Select(p => new XElement(p))));
  using (var fs = arc.AddFile("test1.xml").GetStream
		(FileMode.Open, FileAccess.ReadWrite)) doc1.Save(fs);
  using (var fs = arc.AddFile("test2.xml").GetStream
		(FileMode.Open, FileAccess.ReadWrite)) doc2.Save(fs);
}

// read the files:
using (var arc = ZipArchive.OpenOnStream(str))
{
  var doc1 = XDocument.Load(arc.GetFile("test1.xml").GetStream());
  var doc2 = XDocument.Load(arc.GetFile("test2.xml").GetStream());
  var doc3 = XDocument.Load(arc.GetFile("dir/test3.xml").GetStream());
}

Using the Demo

The demo program ZipArchiveTest using the ZipArchive class is as small as possible and can show the content of Zip archives without any restrictions. Double click to files in the ListBox opens a new window to show the file content as text.

Conclusion

Microsoft should publish its hidden ZipArchive class, but till then, we can use such a simple wrapper to save terabytes of data worldwide.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

D. Christian Ohle
Germany Germany
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionLooks like someone has stolen your article...memberFlorian Storck31mins ago 
QuestionGreat! But...memberCainKellye22 Apr '13 - 1:36 
AnswerRe: Great! But...memberD. Christian Ohle22 Apr '13 - 2:00 
GeneralMy vote of 5memberRalf_13 Mar '13 - 9:07 
GeneralRe: My vote of 5memberD. Christian Ohle13 Mar '13 - 20:52 
GeneralRe: My vote of 5memberRalf_14 Mar '13 - 0:30 
GeneralRe: My vote of 5memberD. Christian Ohle14 Mar '13 - 6:13 
GeneralRe: My vote of 5memberRalf_14 Mar '13 - 23:58 
GeneralMy vote of 5memberDanielSheets11 Mar '13 - 4:58 
GeneralMy vote of 5memberJaap Lamfers12 Feb '13 - 8:32 
Suggestion.NET 3.5 versionmemberStehtimSchilf11 Feb '13 - 8:49 
GeneralThanks!memberrbignu5 Jan '13 - 1:44 
QuestionAwesome!memberWildbird3 Jan '13 - 10:04 
GeneralMy vote of 5memberAwchie13 Nov '12 - 15:28 
GeneralThanks! High 5 DudememberAwchie13 Nov '12 - 15:21 
GeneralMy vote of 5membergelo_one12 Nov '12 - 23:07 
GeneralThanksmemberTheGrandBazaar12 Nov '12 - 4:21 
GeneralMy vote of 5memberElron022 Nov '12 - 13:28 
GeneralMy vote of 5memberCollin Heine21 Sep '12 - 7:57 
GeneralMy vote of 5memberMark Lemke12 Sep '12 - 0:57 
QuestionNo file compression ??memberBillJam119 Aug '12 - 8:25 
AnswerRe: No file compression ??memberBillJam119 Aug '12 - 8:49 
QuestionProblem with non ascii characters in file names [modified]memberNyarlatotep18 Jun '12 - 7:45 
AnswerRe: Problem with non ascii characters in file namesmemberD. Christian Ohle19 Jun '12 - 6:54 
GeneralRe: Problem with non ascii characters in file namesmemberMark Lemke11 Sep '12 - 8:34 
GeneralRe: Problem with non ascii characters in file namesmemberD. Christian Ohle11 Sep '12 - 23:56 
Questionfs.GetStream gives a zero byte length [modified]memberJames Garfield10 Feb '12 - 4:17 
AnswerRe: fs.GetStream gives a zero byte lengthmemberD. Christian Ohle15 Feb '12 - 4:26 
GeneralRe: fs.GetStream gives a zero byte lengthmemberJames Garfield23 Feb '12 - 9:37 
I must have been having a bad day as after reading your reply i went back and revisited this little project and noticed my oversight was not opening a stream to the source file.
 
As you correctly pointed out I was trying zip the file into itself.
 
Thanks for you help!
QuestionhandymemberCIDev15 Jul '11 - 6:08 
AnswerRe: handymemberD. Christian Ohle15 Jul '11 - 11:07 
GeneralRe: handymemberCIDev15 Jul '11 - 13:09 
GeneralRe: handymemberD. Christian Ohle15 Jul '11 - 13:45 
GeneralRe: handymemberCIDev15 Jul '11 - 15:34 
GeneralRe: handymemberD. Christian Ohle15 Jul '11 - 13:59 
GeneralRe: handymemberCIDev15 Jul '11 - 15:36 
GeneralRe: handymemberBillJam119 Aug '12 - 6:59 
GeneralRe: handymemberCIDev9 Aug '12 - 9:04 
GeneralMy vote of 4membertharanga3g13 Jul '11 - 23:35 
GeneralMy vote of 1memberHrvoje Prgeša / Cro11 Jul '11 - 10:52 
QuestionFailed to add a file in zip archivememberJecka11 Jul '11 - 1:36 
AnswerRe: Failed to add a file in zip archivememberD. Christian Ohle11 Jul '11 - 4:11 
GeneralRe: Failed to add a file in zip archivememberJecka11 Jul '11 - 22:52 
GeneralMy vote of 5memberRhuros10 Jul '11 - 23:50 
QuestionInternal Zip library of Microsoft windows is copyrightedmemberMember 47756929 Jun '11 - 1:27 
AnswerRe: Internal Zip library of Microsoft windows is copyrightedmemberD. Christian Ohle30 Jun '11 - 2:19 
GeneralMy vote of 1memberMember 801765320 Jun '11 - 17:27 
GeneralRe: My vote of 1memberD. Christian Ohle20 Jun '11 - 19:54 
GeneralRe: My vote of 1memberSlacker00722 Jun '11 - 0:44 
GeneralRe: My vote of 1memberRhuros10 Jul '11 - 23:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 12 Jun 2011
Article Copyright 2011 by D. Christian Ohle
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid