DotNetZip v1.7.11 - includes managed Zlib, compression levels, Zip64, CF support

Jan 3, 2009 at 11:06 PM
Edited Jan 14, 2009 at 2:05 PM
I wanted to provide an update for the v1.7.11 release, because there are significant changes. The status of this release is still "preview" but it is worth testing and trying out, if you care about any of the new features.

You can get the v1.7.11 release here: 

This release brings changes for USERS of the library, and also for DEVELOPERS who may wish to re-use the DotNetZip source code directly.  Let me take them in turn, comparing the v1.7 stuff to v1.6.

For Users:
  • there is a namespace change: From Ionic.Utils.Zip to Ionic.Zip .   The Utils part of the namespace was meaningless, and as the library gained new features it became more and more evident.  The change means old code will not recompile.  It should be a fairly straightforward port - just do a global search-and-replace , swap "Ionic.Utils" with "Ionic" in all your source modules.  This goes for Using statements (or imports in VB) as well as in code references of fully-qualified type names (Ionic.Zip.ZipFile instead of Ionic.Utils.Zip.ZipFile).   Concurrent with this namespace change, there is a change in the name of the assembly, from Ionic.Utils.Zip.dll to Ionic.Zip.dll.  This may imply changes in your deployment scripts. 
  • the eventing model is completely revamped.  For those of you who have used the v1.6 library with the initial eventing support, I updated the eventing to support much finer-grained notifications.  Previously, the SaveProgress event fired for each Entry saved in the ZipFile.  Now the SaveProgress event fires with each batch of data for every file.  This will allow you to produce a winforms app with two progressbars, for example: one for the progress on the zipfile itself, and one for the progress on the current entry.  I do this in the WinForms example app to illustrate how to do it.   Porting your existing code that depends on eventing will involve some significant effort.  The main ZipFile interface does not change, and if you do not use eventing now, it means no change to you.  But if you do use eventing now, you will have to write some new code to move to v1.7. 
  • v1.7 introduces support for zip64.  With this change the CompressedSize and UncompressedSize properties on the ZipEntry class become Int64, instead of Int32.  This should be a straightforward port for your apps.
  • the TrimVolumeFromFullyQualifiedPaths property has been removed.  This property was unused and unloved, but it is worth mentioning. It was a vestige of a prior broken design where the library encoded drive letters into the zipfile. The behavior and the property are both gone now. 
  • all the ZipFile ctors that take Streams were removed. If you want to save to a stream, call Save(Stream).   I don't know what I was thinking when I introduced those ctors anyway - there were 10 ZipFile constructors (yikes!) and  4 of them were just for the stream support.  All of the 4 were completely unnecessary and redundant - you can do all what you need with streams without these ctors.  So I just yanked them.  This implies a simple code change in your apps.  If you use one of the ctors that takes a stream parameter - you need to move the stream from the ctor to the Save() call. 

Those are the breaking changes.
Also interesting for users of the library, there are also other changes, introducing new features and capabilities.

  • Zip64 support - for large archives.
  • Unicode  improvements.
  • .NET Compact Framework support.  Now the apps you write on .NET CF 2.0 can create and read zip files.
  • inclusion of a managed zlib library, for better compression, and availability on CF2.0.  This last bit is of minor interest if you are just doing ZIP files, but is really interesting if you want to do ZLIB compression in general.  For example, if you are building a SSH tool, or some other socket program that needs to communicate with an agent on the other end that speaks ZLIB.    The Zlib stuff, which I am calling DotNetZlib,  is consumable in its own assembly (Ionic.Zlib.dll), and is completely independent of DotNetZip.  DotNetZip depends on DotNetZlib, but the converse is not true.  Like Ionic.Zip.dll, Ionic.Zlib.dll works on the regular .NET Framework as well as the .NET Compact Framework.  

To take advantage of these new features you will have to write new code. 

And finally, of course there are improvements that you get for free with a recompile.  Things like perf improvements and bug fixes for multi-thread apps.

On the performance improvements - DotNetZip now reads the zip file differently.  To read a really large zip file with thousands of entries now takes 3 seconds, where with v1.6 it could take (literally) minutes.  If you have to manage large zip files with lots of entries, this alone is worth the upgrade.  Also, with the managed ZLIB, the compression is measurably better - like 10-20% better. But YMMV. 

That's it for USERS.

For DEVELOPERS who use the source code, there key changes are in the project structure.

  • New projects in the solution specifically for .NET CF
  • New projects for ZLIB and ZLIB Tests
  • Renamed Projects to clarify what they do.  Think of this as a refactoring of the project organization, not a refactoring of the code.
  • New "meta" projects - that include no source modules.  They merely use ILMerge to combine the ZLIB and ZIP assemblies together.  This preserves the "one assembly to deploy" packaging.  There is one project for CF and one for regular .NET. 
  • A new "Reduced" assembly that compiles DotNetZip to eliminate the SFX support - for those devs who don't want the SFX and could use a smaller DLL.
  • I removed the .pfx and .snk files from the source distribution.  If you want to build a signed assembly, you will have to sign it with your own key.  I will continue to produce a signed assembly for USERS, but I won't redistribute my keys any longer.

I also added new tests and renamed some source files and etc.  Nothing really major there.   Of note - the replacement of System.IO.Compression with DotNetZlib required changes in just 3 lines in the source.  Every mention of System.IO.Compression.DeflateStream was replaced with Ionic.Zlib.DeflateStream.  Simple.  Easy. 

What has not changed:  DotNetZip continues to use CodePlex to host the project.  The library continues to get good reviews, and good suggestions and feedback from users like yourself.  Thanks for pitching in.  Finally, DotNetZip continues to be "donationware".  (And DotNetZlib is also).  It is free to use, and is open source.  But if you find value in the library, please consider donating:

As always, I would love to hear feedback and experiences on any of these changes.

Jan 4, 2009 at 8:38 AM
Edited Jan 4, 2009 at 12:04 PM
Hi Chesso,

Seems that files are still read twice ? I don't understand why you still need that because with the new algorythm compression you should don't have to do that.

Also I get a lot of problems with the main solution (SLN).
- some reference to "Windows Mobile 6.0 Standard SDK" ?
- pfx file is still referenced in the source and in some csproj files
- Path to ILMerge is incorrect for me, you should redistribute ILMerge with your solution and make a reference to the ILMerge local copy

Also I get an error when I am trying to ZIP a folder that contains 2 files (folder size : 5Go) with the WinForms test application (note that I select "As necessary" for the ZIP64 option).
You can get a screenshot of the error here :

What is the default Zip compression level using the WinForm example ?

Jan 4, 2009 at 2:33 PM
I have done some benchmarking on zipping a file (650mo)  :
- DotNetZip : 2 min 20s (flavor : traditionnal zip / encoding : utf-8 / ZIP64 : As necessary)
- DotNetZip : 4 min 25s (flavor : traditionnal zip / encoding : utf-8 / ZIP64 : As necessary / compression level : ?)
- WinRAR 3.80 : 1 min 20s (compression method : Normal / Compression type : Deflate)
- SharpZipLib 0.855 : 3 min 15s (compression method : Normal / Compression type : Deflate)
- 7Zip 4.60 : 3 min 16s (compression method : Normal / Compression type : Deflate)

Compression performance are worst since or I am miss something ?
Jan 4, 2009 at 4:25 PM
thanks for the feedback, thanks for trying this out.

The performance numbers you provide are interesting. 

The compression used by the library is BEST in v1.7.11. 

I am right now modifying the the ZipFile to expose a property to allow the application to set this.
And also the WinForms app to expose that property in the UI.  I will let you know what I find.

To answer your other observations -
- the .pfx issue:  I need to figure out how to make the .sln work for people without the .pfx, as well as for myself (with the PFX).
- the Windows Mobile SDK issue:  Same thing.
- ILMerge - same thing.

I am not sure about the error message you experienced.  I will have to look into this.
Jan 4, 2009 at 5:42 PM
Edited Jan 4, 2009 at 10:50 PM
Hey Dom,
In my tests, selecting different compression levels gives different speed.
I have a basket of files, totalling about 76mb all zipped up (at best compression).
The times:

0:51 - compression: NONE
1:09 - compression: DEFAULT
2:08 - compression: BEST

Interestingly, the BEST compression delivered a zip that was 42% of the size of the original files.
This was only slightly better than the default compression, which delivered 45%. 

update 1: I just uploaded v1.7.1.12 that includes the settable CompressionLevel.  You can test it yourself. 

update 2:  Looking at the exception you experienced in the WinForms app - I am guessing it is a problem with an out-of-range Value on a progressBar control.   I just looked at the code and I believe I see how it can reach an out-of-range value.  The v1.7.1.13 update, available now, corrects this problem. Give it a try.
Jan 5, 2009 at 8:34 PM
I completed my previous test with (with the same file) :
- LEVEL0_NONE : 47 sec
- NONE : 1 min 09
- LEVEL1_BEST_SPEED : 1 min 55
- BEST_SPEED : 1 min 55
- DEFAULT : 2 min 12
- LEVEL6_DEFAULT : 2 min 16

When looking the progressbar, I see that there is 2 phases on a the file to zip.
1st phase : read ?
2nd phase : compression ?

Conclusion : performance are great ;)

Thanks for the duration that you add on the form !

I still have the same error on the 5Go file :
Jan 6, 2009 at 12:51 AM
Good - I'm glad the perf got better.   I don't know WHY it got so much better for you, though.  I am surprised.  

the DEFAULT is the same as LEVEL6_DEFAULT.  and BEST_SPEED == LEVEL1_BEST_SPEED, etc.   There are some synonyms.  I will remove them from the UI. 

Also  - don't forget there is still a built-in sleep in the winforms sample app.  I put it in there to help demonstrate the progress bar.  Maybe I should remove it.  You would get even faster performance.

as for 2 phases in the progressbar - no, it is not read + compression.    It is encode pass1 and encode pass2.  The library still works the same way:  if the first pass of the compression inflates the data, the library will do another pass (reading the same file again), without compression.   That should happen less often with the zlib stuff, but it may still happen.
Jan 9, 2009 at 10:19 PM
Edited Jan 9, 2009 at 10:30 PM
Hi Cheeso,

I still have the same error in the Winforms application when zipping a 5Go file.
This is the same problem reported in my previous message.

One question :
Do you know how to avoid the 2nd pass (when first pass inflate the file) ?

Jan 9, 2009 at 10:39 PM
Hey Dom, 

I will grab that file and see if I can duplicate the problem you are having.

Try this to avoid reading twice: 

        /// public bool NeverReadTwice(long uncompressed, long compressed, string filename)
        /// {
        ///     return false;
        /// }
        /// public void CreateTheZip()
        /// {
        ///     using (ZipFile zip = new ZipFile())
        ///     {
        ///         // set the callback before adding files to the zip
        ///         zip2.WillReadTwiceOnInflation = NeverReadTwice;
        ///         zip2.AddFile(filename1);
        ///         zip2.AddFile(filename2);
        ///         zip2.Save(ZipFileToCreate);
        ///     }
        /// }
Jan 10, 2009 at 11:02 AM
Edited Jan 10, 2009 at 1:20 PM
Hi Cheeso,

The callback works great, thanks

An idea :
May be you should implement a default callback with a smart calculed ratio (compressed/uncompressed) value.
Jan 14, 2009 at 7:25 AM
Edited Jan 14, 2009 at 7:25 AM
   when will the v1.7 be released? any certain date?
Jan 14, 2009 at 1:01 PM
I'd guess that within the next 3 weeks I will release v1.7.

I don't know exactly when. I don't choose a date for release; instead I try to depend on user feedback and demand to know when a release is stable enough.
Even now there are a few bug reports coming in on the new things in v1.7. 

Jan 17, 2009 at 10:07 PM
Edited Jan 18, 2009 at 8:25 AM
Hi Cheeso,

Have you reproduce the problem with the big file ?
Still download problems ?

I have upload the file here :

Jan 18, 2009 at 2:19 PM
I  have not reproduced the problem, never was able to download your file successfully. 
I am trying the download again now.
Feb 5, 2009 at 12:17 PM
Hi Cheeso,

Did you have successfully download the file and reproduced the error ?
Feb 5, 2009 at 6:02 PM
No, I was never able to download that file,
and I was never able to reproduce the error.
Feb 10, 2009 at 5:15 PM
I also had DomZ's issue and was able to reproduce it with a large fiile (Over 2 GB in size) "Exception while Zipping -2147481600".  The Exception gets thrown in StepEntryProgress in the Form of the Win Forms Zip Example.  The variable xferred is declared as an integer and gets set to BytesTransferred.  If you try to zip a file over 2GB in size (2147483648 bytes, Integer can only handle 2147483647) the xferred will get an overflow error.  It needs to be an Int64 or handle it some other way.

Also a file is not getting compressed if it is more than 2 GB in size, I am going to look into that this afternoon and will let you know what I find.

By the way I think the library is great.
Feb 10, 2009 at 6:29 PM

OK, Mr Z1P, very clear.

What version of the source code are you referring to? 

I think DomZ reported that specific problem previously, and I fixed it, as far as I know. The current StepEntryProgress looks like this:


                if (!_saveCanceled)
                    if (this.progressBar2.Maximum == 1)
                        // reset
                        Int64 entryMax = e.TotalBytesToTransfer;
                        Int64 absoluteMax = System.Int32.MaxValue;
                        _progress2MaxFactor = 0;
                        while (entryMax > absoluteMax)
                            entryMax /= 2;
                        if ((int)entryMax < 0) entryMax *= -1;
                        this.progressBar2.Maximum = (int)entryMax;
                        lblStatus.Text = String.Format("{0} of {1} files...({2})",
                            _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName);

                    int xferred = e.BytesTransferred >> _progress2MaxFactor;

                    this.progressBar2.Value = (xferred >= this.progressBar2.Maximum)
                        ? this.progressBar2.Maximum
                        : xferred;


The idea is that xferred is constrained to an int32, by right-shifting the long e.BytesTransferred by progress2MaxFactor.

Feb 10, 2009 at 8:02 PM

Sorry I did not look at this close enough of the first time obv.  I am on the latest version (  The line of code that blows up is actually:

 this.progressBar2.Value = (xferred >= this.progressBar2.Maximum)
                        ? this.progressBar2.Maximum
                        : xferred;

Here is what I think is happening:

I have a file that has a length of 2179458560 (just over 2gb).  The maximum integer size is 2147483647 so the file length has exceeded the max int by 31974913.  So in StepEntryProgress as e.BytesTransferred is being updated it works fine until it gets to a size of 2147483647.  When it gets to max int, BytesTransfered goes out of range and starts from the smallest negative value.  So in my example:

BytesTransfered works fine as the number of bytes grows to the 2 GB size 2147483647.
Once it surpasses 2 GB BytesTransfered restarts at at -2147483647 and adds on the additional 31974913 bytes it needs to transfer resulting in -2115508736. 
So xferred gets set to a negative number onces over 2 GB which is not >= this.progressBar2.Maximum so it trys to set this.ProgrssBar2.Value = to the negative number which is less than the minimum value and the exception gets thrown.

I hope this makes sense.  Let me know if I confused you.




Feb 11, 2009 at 6:07 AM
oh, yes, I see now.  There's a basic error.  BytesTransferred in the ZipProgressEventArgs should not be an int.  It needs to be a long. 
Thanks for catching this.  When I updated the ProgressEvent stuff, I corrected the TotalBytes property but not the BytesTransferred. 
Looking at the code, there are similar int-vs-long problems in a couple modules .   It's not just a problem in the WinForms example.

An oversight.  I will fix!
Feb 11, 2009 at 1:57 PM
I think the long vs. int thing is also causing files larger than 2 GBs to not compress.  So the changes to the other modules will probably fix that issue as well.  I change several ints to longs and was able to get the file to compress.  Some of them being:
ZipEntry -> fileLength
ZipEntry -> fileLength = (int) fi.Length to fileLength = fi.Length
Crc32 -> TotalBytesSlurped
Crc32 -> TotalBytesRead

I'm sure you probably had these but I thought I would pass along what I found.

Feb 11, 2009 at 5:08 PM

Yes, thanks, I did find those.   Check the v1.7.2.3 release - it has the updates.
You may be right that the truncation has caused problems with compression.  Only way to know is to test.