Great Utility
SharpZipLib is a great little library that helps you programmatically compress/decompress zip archives. If your needs aren't too exotic (ie. you need to programmatically zip/unzip a series of files/folders) this could very well be your ticket.
You've probably heard of it before (it's been around for quite a while), some sample usage might look like this (compresses a file).
using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipFilePath)))
{
//Compression level 0-9 (9 is highest)
zipStream.SetLevel(GetCompressionLevel());
//Add an entry to our zip file
ZipEntry entry = new ZipEntry(Path.GetFileName(sourceFilePath));
entry.DateTime = DateTime.Now;
zipStream.PutNextEntry(entry);
byte[] buffer = new byte[4096];
int byteCount = 0;
using (FileStream inputStream = File.OpenRead(sourceFilePath))
{
byteCount = inputStream.Read(buffer, 0, buffer.Length);
while (byteCount > 0)
{
zipStream.Write(buffer, 0, byteCount);
byteCount = inputStream.Read(buffer, 0, buffer.Length);
}
}
}
This is pretty normal usage. It adds a zip entry to an archive and creates said archive. What might confuse you though is the error you'll get if you try to to unpack the archive using a legacy unzip tool (ie. the stock Windows XP decompression tool).
The stock Windows XP extraction tool won't be able to unpack the archive and will complain about the archive being "invalid or corrupted" if you try to extract the archive contents.
Zip64 Extensions
What's happening here is that the utility is enabling Zip64 extensions for the archive, and some older utilities can't read Zip64 Extensions. You could simply turn off Zip64 Extensions, but this will cause problems when you start adding files larger than 4GB to your archive.
A better solution is to make a mild tweak to the way we add files to the archive. By specifying the size of the file we're adding, the ZipOutputStream can decide whether or not to use the Zip64 extensions. If we don't need them then they'll be turned off automatically. The mild tweak below fixes the error from the above code:
...
ZipEntry entry = new ZipEntry(Path.GetFileName(sourceFilePath));
entry.DateTime = DateTime.Now;
/* By specifying a size, SharpZipLib will turn on/off UseZip64 based on the file sizes. If Zip64 is ON
* some legacy zip utilities (ie. Windows XP) who can't read Zip64 will be unable to unpack the archive.
* If Zip64 is OFF, zip archives will be unable to support files larger than 4GB. */
entry.Size = new FileInfo(sourceFilePath).Length;
zipStream.PutNextEntry(entry);
...
Hope that helps someone. That error drove me crazy for a while and I didn't find much via Google.
Best,
Tyler
17 comments:
The timing of this post was great. I had a web app using the SharpZipLib code and had no issues using my current Winzip or 7-zip.
Users with Winzip 8.0, Freezip, and the XP Compressed Folders were encountering problems. What I noticed was if I opened the old zip file with XP Compressed Folders, it would display both the packed size and original size as 4Gb which certainly coincides with the Zip64 comment.
Thank You for this post!
Excellent post, thanks for the info!
Very nice, would have taken me forever to fix this error. Thanks!
Thank you.
This is also the workaround for the error if you add an empty file (0 bytes) via SharpZipLib 0.85.5 to an ZIP archive. WinZip 10.0 consider this files as invalid: "Error: invalid compressed data to inflate".
Thank you for this post.
Tom
Still not correct. This is a bug in SharpZipLib
This solved my problem! I was wondering myself why it wouldn't open with the XP compressed folders. I have WinZip installed and it wasn't a problem.
Thanks!
Thanks, your comment was very useful.
That works for me:
private void ZipFiles(string sActivityType, bool bPrintedOnly)
{
List filesNames_Guid = GenerateFilesList(sActivityType, bPrintedOnly);
Guid filename = Guid.NewGuid();
FileStream ostream;
byte[] obuffer;
//generic and unique name for the zipped file, needs to be removed afterwards
string outPath = Server.MapPath("~/TMP") + @"\" + filename.ToString() + ".zip";
ZipOutputStream oZipStream = new ZipOutputStream(System.IO.File.Create(outPath)); // create zip stream
//oZipStream.UseZip64 = UseZip64.Off;
ZipEntry oZipEntry;
for (int i = 0; i < filesNames_Guid.Count - 1; i = i + 2)
{
oZipEntry = new ZipEntry(filesNames_Guid[i]);
// start of the fix.
FileInfo MyFileInfo = new FileInfo(Server.MapPath("~/ArtifactLibrary") + "\\" + filesNames_Guid[i + 1]);
oZipEntry.DateTime = MyFileInfo.CreationTime;
oZipEntry.Size = MyFileInfo.Length;
// end of the fix.
oZipStream.PutNextEntry(oZipEntry);
ostream = System.IO.File.OpenRead(Server.MapPath("~/ArtifactLibrary") + "\\" + filesNames_Guid[i + 1]);
obuffer = new byte[ostream.Length];
ostream.Read(obuffer, 0, obuffer.Length);
oZipStream.Write(obuffer, 0, obuffer.Length);
ostream.Close();
}
oZipStream.Finish();
HttpContext.Current.Response.AddHeader("Content-Disposition", ("attachment; filename=" + ViewState["Name_Selected"] + " " + sActivityType + (bPrintedOnly ? " PrintedOnly" : "") + ".zip"));
HttpContext.Current.Response.AddHeader("Content-Length", oZipStream.Length.ToString());
HttpContext.Current.Response.ContentType = "application/octet-stream";
oZipStream.Close();
HttpContext.Current.Response.TransmitFile(outPath);
}
You rock, completely solved my problem. I am zipping in C#, unzipping in Java, which was error'ing out with "invalid entry size (expected 4294967295 but got xxx bytes)" before your fix.
Thank you!
Thanks ... because you helped a lot, but a more correct answer to this kind of problem is to simply turn zip64 off, like this:
zipOutput.UseZip64 = UseZip64.Off;
How is that a "solution"?
Use the 7-zip option to avoid having Zip64 used on <4gb files... which XP doesn't have a problem with anyway.
If the file is >4gb, Windows can't open them anyway... with Zip64 or not.
Doesn't that mean it won't work either way?
Thank is exactly what i was looking for. Thanks a lot.
I was searching for a work-around, and saw this post. It looks like this is a fix to help people avoid FUTURE problems--could you possibly help me with a fix for something at hand?
I'm trying to unzip a password protected archive containing two video files, 486mb and 286mb. When I go to extract files/open archive, and put in password, I receive this message: "Error: invalid compressed data to inflate."
I need a workaround to rescue and recover my files. Is this possible?
@Ihsan: As a workaround to extract zip files that have this problem, you can copy them to a Windows7 machine. There it is possible to open the ZIP archive.
Thanks for the solution. Solved my problem.. :)
Real helpful! Thanks.
Post a Comment