Click here to Skip to main content
11,496,146 members (562 online)
Click here to Skip to main content

Tagged as

C# Use Zip Archives without External Libraries

, 12 Jun 2011 CPOL 109.1K 6.1K 146
C# use Zip archives without external libraries
The site is currently in read-only mode for maintenance. Posting of new items will be available again shortly.

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)

Share

About the Author

No Biography provided

Comments and Discussions

 
Suggestion.NET 3.5 version Pin
StehtimSchilf11-Feb-13 9:49
memberStehtimSchilf11-Feb-13 9:49 
GeneralThanks! Pin
rbignu5-Jan-13 2:44
memberrbignu5-Jan-13 2:44 
QuestionAwesome! Pin
Wildbird3-Jan-13 11:04
memberWildbird3-Jan-13 11:04 
GeneralMy vote of 5 Pin
Awchie13-Nov-12 16:28
memberAwchie13-Nov-12 16:28 
GeneralThanks! High 5 Dude Pin
Awchie13-Nov-12 16:21
memberAwchie13-Nov-12 16:21 
GeneralMy vote of 5 Pin
gelo_one13-Nov-12 0:07
membergelo_one13-Nov-12 0:07 
GeneralThanks Pin
TheGrandBazaar12-Nov-12 5:21
memberTheGrandBazaar12-Nov-12 5:21 
GeneralMy vote of 5 Pin
Elron022-Nov-12 14:28
memberElron022-Nov-12 14:28 
GeneralMy vote of 5 Pin
Collin Heine21-Sep-12 8:57
memberCollin Heine21-Sep-12 8:57 
GeneralMy vote of 5 Pin
Mark Lemke12-Sep-12 1:57
memberMark Lemke12-Sep-12 1:57 
QuestionNo file compression ?? Pin
BillJam119-Aug-12 9:25
memberBillJam119-Aug-12 9:25 
AnswerRe: No file compression ?? Pin
BillJam119-Aug-12 9:49
memberBillJam119-Aug-12 9:49 
QuestionProblem with non ascii characters in file names [modified] Pin
Nyarlatotep18-Jun-12 8:45
memberNyarlatotep18-Jun-12 8:45 
AnswerRe: Problem with non ascii characters in file names Pin
D. Christian Ohle19-Jun-12 7:54
memberD. Christian Ohle19-Jun-12 7:54 
Hello Nyarlatotep
you are right, I could reproduce it with a filename like "é.txt".
But it is no problem with Reflection.
Internal the MS...ZipArchive has a field _blockManager._encoding and this is as Type fixed to System.Text.ASCIIEncoding.
It means we can not change the encoding.
It seems to be a limitation, but there is always a way, unfortunately I found nothing.
Would be interesting if someone has an idea.
Regards
Christian
GeneralRe: Problem with non ascii characters in file names Pin
Mark Lemke11-Sep-12 9:34
memberMark Lemke11-Sep-12 9:34 
GeneralRe: Problem with non ascii characters in file names Pin
D. Christian Ohle12-Sep-12 0:56
memberD. Christian Ohle12-Sep-12 0:56 
Questionfs.GetStream gives a zero byte length [modified] Pin
James Garfield10-Feb-12 5:17
memberJames Garfield10-Feb-12 5:17 
AnswerRe: fs.GetStream gives a zero byte length Pin
D. Christian Ohle15-Feb-12 5:26
memberD. Christian Ohle15-Feb-12 5:26 
GeneralRe: fs.GetStream gives a zero byte length Pin
James Garfield23-Feb-12 10:37
memberJames Garfield23-Feb-12 10:37 
Questionhandy Pin
CIDev15-Jul-11 7:08
memberCIDev15-Jul-11 7:08 
AnswerRe: handy Pin
D. Christian Ohle15-Jul-11 12:07
memberD. Christian Ohle15-Jul-11 12:07 
GeneralRe: handy Pin
CIDev15-Jul-11 14:09
memberCIDev15-Jul-11 14:09 
GeneralRe: handy Pin
D. Christian Ohle15-Jul-11 14:45
memberD. Christian Ohle15-Jul-11 14:45 
GeneralRe: handy Pin
CIDev15-Jul-11 16:34
memberCIDev15-Jul-11 16:34 
GeneralRe: handy Pin
D. Christian Ohle15-Jul-11 14:59
memberD. Christian Ohle15-Jul-11 14:59 
GeneralRe: handy Pin
CIDev15-Jul-11 16:36
memberCIDev15-Jul-11 16:36 
GeneralRe: handy Pin
BillJam119-Aug-12 7:59
memberBillJam119-Aug-12 7:59 
GeneralRe: handy Pin
CIDev9-Aug-12 10:04
memberCIDev9-Aug-12 10:04 
GeneralMy vote of 4 Pin
tharanga3g14-Jul-11 0:35
membertharanga3g14-Jul-11 0:35 
GeneralMy vote of 1 Pin
Hrvoje Prgeša / Cro11-Jul-11 11:52
memberHrvoje Prgeša / Cro11-Jul-11 11:52 
QuestionFailed to add a file in zip archive Pin
Jecka11-Jul-11 2:36
memberJecka11-Jul-11 2:36 
AnswerRe: Failed to add a file in zip archive Pin
D. Christian Ohle11-Jul-11 5:11
memberD. Christian Ohle11-Jul-11 5:11 
GeneralRe: Failed to add a file in zip archive Pin
Jecka11-Jul-11 23:52
memberJecka11-Jul-11 23:52 
GeneralMy vote of 5 Pin
Rhuros11-Jul-11 0:50
memberRhuros11-Jul-11 0:50 
QuestionInternal Zip library of Microsoft windows is copyrighted Pin
Member 47756929-Jun-11 2:27
memberMember 47756929-Jun-11 2:27 
AnswerRe: Internal Zip library of Microsoft windows is copyrighted Pin
D. Christian Ohle30-Jun-11 3:19
memberD. Christian Ohle30-Jun-11 3:19 
GeneralMy vote of 1 Pin
Member 801765320-Jun-11 18:27
memberMember 801765320-Jun-11 18:27 
GeneralRe: My vote of 1 Pin
D. Christian Ohle20-Jun-11 20:54
memberD. Christian Ohle20-Jun-11 20:54 
GeneralRe: My vote of 1 Pin
Slacker00722-Jun-11 1:44
memberSlacker00722-Jun-11 1:44 
GeneralRe: My vote of 1 Pin
Rhuros11-Jul-11 0:49
memberRhuros11-Jul-11 0:49 
GeneralMy vote of 5 Pin
Filip D'haene19-Jun-11 5:10
memberFilip D'haene19-Jun-11 5:10 
GeneralMy vote of 5 Pin
shenron13-Jun-11 22:43
membershenron13-Jun-11 22:43 
GeneralInteresting idea [modified] Pin
RudolfHenning13-Jun-11 20:16
memberRudolfHenning13-Jun-11 20:16 
GeneralRe: Interesting idea Pin
D. Christian Ohle13-Jun-11 21:42
memberD. Christian Ohle13-Jun-11 21:42 
GeneralRe: Interesting idea Pin
RudolfHenning13-Jun-11 21:48
memberRudolfHenning13-Jun-11 21:48 
GeneralMy vote of 5 Pin
Yvan Rodrigues13-Jun-11 16:57
memberYvan Rodrigues13-Jun-11 16:57 
GeneralNever use internal classes/methods Pin
TimMerksem13-Jun-11 12:18
memberTimMerksem13-Jun-11 12:18 
GeneralRe: Never use internal classes/methods Pin
D. Christian Ohle13-Jun-11 13:12
memberD. Christian Ohle13-Jun-11 13:12 
JokeRe: Never use internal classes/methods Pin
TimMerksem13-Jun-11 13:16
memberTimMerksem13-Jun-11 13:16 
GeneralSecurity Implications Pin
Nicholas Carey13-Jun-11 7:49
memberNicholas Carey13-Jun-11 7:49 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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