21

In my c# code I am trying to create a zip folder for the user to download in the browser. So the idea here is that the user clicks on the download button and he gets a zip folder.

For testing purpose I am using a single file and zipping it but when it works I will have multiple files.

Here is my code

var outPutDirectory = AppDomain.CurrentDomain.BaseDirectory;
string logoimage = Path.Combine(outPutDirectory, "images\\error.png"); // I get the file to be zipped

HttpContext.Current.Response.Clear();
HttpContext.Current.Response.BufferOutput = false;
HttpContext.Current.Response.ContentType = "application/zip";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=pauls_chapel_audio.zip");


using (MemoryStream ms = new MemoryStream())
     {
          // create new ZIP archive within prepared MemoryStream
          using (ZipArchive zip = new ZipArchive(ms))
             {
                    zip.CreateEntry(logoimage);
                    // add some files to ZIP archive

                    ms.WriteTo(HttpContext.Current.Response.OutputStream);
             }
     }

When I try this thing it gives me this error

Central Directory corrupt.

[System.IO.IOException] = {"An attempt was made to move the position before the beginning of the stream."}

Exception occurs at

using (ZipArchive zip = new ZipArchive(ms))

Any thoughts?

Community
  • 1
  • 1
mohsinali1317
  • 4,255
  • 9
  • 46
  • 85
  • Just a note if you are trying to *unzip* files: If the zip is located in your OneDrive folder and OneDrive is turned off and the file is set to online mode, you'll get the same error. Just turn OneDrive on again and it should work. – Nicke Manarin Dec 15 '19 at 02:42

1 Answers1

35

You're creating the ZipArchive without specifying a mode, which means it's trying to read from it first, but there's nothing to read. You can solve that by specifying ZipArchiveMode.Create in the constructor call.

Another problem is that you're writing the MemoryStream to the output before closing the ZipArchive... which means that the ZipArchive code hasn't had a chance to do any house-keeping. You need to move the writing part to after the nested using statement - but note that you need to change how you're creating the ZipArchive to leave the stream open:

using (MemoryStream ms = new MemoryStream())
{
    // Create new ZIP archive within prepared MemoryStream
    using (ZipArchive zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
    {
        zip.CreateEntry(logoimage);
        // ...
    }        
    ms.WriteTo(HttpContext.Current.Response.OutputStream);
 }
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Still getting the same error. Exception occurs at using (ZipArchive zip = new ZipArchive(ms)) – mohsinali1317 Nov 13 '15 at 07:07
  • 1
    @ChaudhryMohsinAli: Ah. It would have helped if you'd said that to start with. – Jon Skeet Nov 13 '15 at 07:08
  • I just found out myself where the error was occurring. – mohsinali1317 Nov 13 '15 at 07:08
  • 1
    @ChaudhryMohsinAli: The lesson to learn is always to include a full stack trace when you post an error. I'm still investigating. – Jon Skeet Nov 13 '15 at 07:10
  • 1
    @ChaudhryMohsinAli: See my edit. I've tested this code and it appears to work fine. – Jon Skeet Nov 13 '15 at 07:13
  • Now I am having another error as it seems. The image which I used for test when I open it after extracting the zip folder it has nothing in it. The image size is 0 bytes. – mohsinali1317 Nov 13 '15 at 07:49
  • 2
    @ChaudhryMohsinAli: If this is running from ASP.NET, then perhaps the file isn't where you think it is... you may want to resolve the filename relative to the web context first. – Jon Skeet Nov 13 '15 at 08:20
  • any indicators on how to do that? – mohsinali1317 Nov 13 '15 at 08:23
  • 3
    @ChaudhryMohsinAli: I'm not an ASP.NET developer, but I believe it depends on what version you're using etc. `HttpServerUtility.MapPath` is one way, but there may be better approaches now. – Jon Skeet Nov 13 '15 at 08:39