Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid zip file after creating it with System.IO.Compression

Tags:

I'm trying to create a zip file that contains one or more files.
I'm using the .NET framework 4.5 and more specifically System.IO.Compression namespace.
The objective is to allow a user to download a zip file through a ASP.NET MVC application.
The zip file is being generated and sent to the client but when I try to open it by doing double click on it I get the following error:
Windows cannot open the folder. The compressed (zipped) folder ... is invalid.
Here's my code:

[HttpGet] public FileResult Download() {     var fileOne = CreateFile(VegieType.POTATO);     var fileTwo = CreateFile(VegieType.ONION);     var fileThree = CreateFile(VegieType.CARROT);      IEnumerable<FileContentResult> files = new List<FileContentResult>() { fileOne, fileTwo, fileThree };     var zip = CreateZip(files);      return zip; }  private FileContentResult CreateFile(VegieType vType) {     string fileName = string.Empty;     string fileContent = string.Empty;      switch (vType)     {         case VegieType.BATATA:             fileName = "batata.csv";             fileContent = "THIS,IS,A,POTATO";             break;         case VegieType.CEBOLA:             fileName = "cebola.csv";             fileContent = "THIS,IS,AN,ONION";             break;         case VegieType.CENOURA:             fileName = "cenoura.csv";             fileContent = "THIS,IS,A,CARROT";             break;         default:             break;     }      var fileBytes = Encoding.GetEncoding(1252).GetBytes(fileContent);     return File(fileBytes, MediaTypeNames.Application.Octet, fileName); }  private FileResult CreateZip(IEnumerable<FileContentResult> files) {     byte[] retVal = null;      if (files.Any())     {         using (MemoryStream zipStream = new MemoryStream())         {             using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, false))             {                 foreach (var f in files)                 {                     var entry = archive.CreateEntry(f.FileDownloadName, CompressionLevel.Fastest);                     using (var entryStream = entry.Open())                     {                         entryStream.Write(f.FileContents, 0, f.FileContents.Length);                         entryStream.Close();                     }                 }                  zipStream.Position = 0;                 retVal = zipStream.ToArray();             }         }     }      return File(retVal, MediaTypeNames.Application.Zip, "horta.zip"); } 

Can anyone please shed some light on why is windows saying that my zip file is invalid when I double click on it.
A final consideration, I can open it using 7-Zip.

like image 790
César Lourenço Avatar asked Oct 21 '16 11:10

César Lourenço


People also ask

Why is my Compressed ZIP file invalid?

Your Zip file is invalid because of errors like virus infection, or an incomplete download from the internet. Both of these factors can cause a Zip file to become corrupt or damaged, thus leading to the error message, "The Compressed (zipped) folder is invalid".

What does invalid zip mean?

You will see this error when the zip or postal code of your address does not match your purchasing card. Simply review what the postal or zip code of your purchasing card is, and re-enter the correct information to proceed.

How do I change the compression on a zip file?

Press and hold (or right-click) the file or folder, select (or point to) Send to, and then select Compressed (zipped) folder. A new zipped folder with the same name is created in the same location. To rename it, press and hold (or right-click) the folder, select Rename, and then type the new name.


2 Answers

You need to get the MemoryStream buffer via ToArray after the ZipArchive object gets disposed. Otherwise you end up with corrupted archive.

And please note that I have changed the parameters of ZipArchive constructor to keep it open when adding entries.

There is some checksumming going on when the ZipArchive is beeing disposed so if you read the MemoryStream before, it is still incomplete.

    private FileResult CreateZip(IEnumerable<FileContentResult> files)     {         byte[] retVal = null;          if (files.Any())         {             using (MemoryStream zipStream = new MemoryStream())             {                 using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))                 {                     foreach (var f in files)                     {                         var entry = archive.CreateEntry(f.FileDownloadName, CompressionLevel.Fastest);                         using (BinaryWriter writer = new BinaryWriter(entry.Open()))                         {                                                                writer.Write(f.FileContents, 0, f.FileContents.Length);                             writer.Close();                         }                     }                      zipStream.Position = 0;                 }                 retVal = zipStream.ToArray();             }         }          return File(retVal, MediaTypeNames.Application.Zip, "horta.zip");     } 
like image 82
michalh Avatar answered Sep 20 '22 15:09

michalh


Just return the stream...

private ActionResult CreateZip(IEnumerable files) {     if (files.Any())     {         MemoryStream zipStream = new MemoryStream();         using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, false))         {             foreach (var f in files)             {                var entry = archive.CreateEntry(f.FileDownloadName, CompressionLevel.Fastest);                using (var entryStream = entry.Open())                {                    entryStream.Write(f.FileContents, 0, f.FileContents.Length);                    entryStream.Close();                }            }          }          zipStream.Position = 0;         return File(zipStream, MediaTypeNames.Application.Zip, "horta.zip");     }      return new EmptyResult(); }
like image 27
David Avatar answered Sep 18 '22 15:09

David