downloading and decompression of a zip folder

Mar 15, 2010 at 3:33 PM

I hope someone can help me with the following issue:

When I try to download a zip folder to my Mac hard drive through Safari, the automatic decompression does not work. Also, the foldername gets to be extended - for example if the folder name is "abc.zip" it becomes "abc.zip, filename=abc.zip"

This happens only on Mac, using Safari. All works very well on pc platforms and other browsers. Does anyone know of any known issue or a solution to this?

thanks

Coordinator
Mar 15, 2010 at 5:38 PM

show me the code you use to generate and download the ZIP file.

Mar 15, 2010 at 5:51 PM

Hi Cheeso, thanks a lot for taking a look at this. here is the code:

Private Sub ZipFolder(ByVal FolderToZip As String)
        Response.Clear()
        Response.BufferOutput = False

        Dim archiveName As String = _
            Path.GetFileName(FolderToZip) & "_" & (DateTime.Now.ToString("yyyyMMMdd_HHmmss")) & ".zip"

        Response.ContentType = "application/zip"
        Response.AddHeader("content-disposition", "filename=" + archiveName)
        Response.AddHeader("content-disposition", "filename=" + archiveName)

        Using zip As ZipFile = New ZipFile()
            zip.AddDirectory(FolderToZip)
            zip.Save(Response.OutputStream)
            zip.Dispose()
            ' Send the output to the client.
            Response.Flush()

        End Using
        HttpContext.Current.ApplicationInstance.CompleteRequest()
        ' Response.Close()

    End Sub

Mar 15, 2010 at 5:53 PM

I just want to emphasize that this works with all browsers on pc - it is only on mac and safari that i have this problem.

thanks again.

Mar 15, 2010 at 6:25 PM

I fixed the file name issue myslef - it was a duplicate of two lines in my code. However, the decompression is still an issue.

Coordinator
Mar 15, 2010 at 6:36 PM
Edited Mar 15, 2010 at 8:01 PM

You should make some changes in your code:

  1. Definitely use Response.Close insteead of ApplicationInstance.CompleteRequest()
  2. do you really have two of these lines?  Response.AddHeader("content-disposition", "filename=" + archiveName) 
    if so, remove one.
  3. Change the remaining call to Response.AddHeader to be:
      Response.AddHeader("Content-Disposition", "inline; filename=" & chr(34) & archiveName & chr(34))
  4. Remove the call to Response.Flush and zip.Dispose . They are both unnecessary.

All these changes should be made in any case; the code is not correct as you have it now. 

The modified code you should have, after those changes, looks like this:

Private Sub ZipFolder(ByVal FolderToZip As String)
    Response.Clear()
    Response.BufferOutput = False

    Dim archiveName As String = _
        Path.GetFileName(FolderToZip) & "_" & (DateTime.Now.ToString("yyyyMMMdd_HHmmss")) & ".zip"

    Response.ContentType = "application/zip"
    Response.AddHeader("Content-Disposition", "filename=" & chr(34) & archiveName & chr(34))

    Using zip As ZipFile = New ZipFile()
        zip.AddDirectory(FolderToZip)
        zip.Save(Response.OutputStream)
    End Using
    Response.Close()
End Sub

This should fix your problem.

Now, some further explanation, in case you are interested:

There was? is?  a known behavior in Safari - it ignores the filename parameter in the Content-Disposition header.  It has been called "a problem" or "a bug" but I hesitate to label it that way, because the Content-Disposition header (see IETF RFC 2183) is not formally part of the HTTP standard, and so Safari is not incorrect in behaving differently, if you get my meaning.  Most other browsers implement Content-Disposition, but there are some issues with it, and it's truly a fuzzy area of the HTTP protocol.  And this is why you are seeing the difference in behaivor. It has nothing to do with DotNetZip.  It's just a difference in the way Safari handles the header. 

If the problem still is not solved, even after the above changes, then I don't know what you can do. 

As I said, this is not a DotNetZip issue; it's a Safari/HTTP thing.  So you may want to try a support forum for Mac developers or web developers for more hints. 

 

Mar 15, 2010 at 7:07 PM

Thanks. I know what you mean with the HTTP standard.

I changed my code,  the decompression is still an issue. Will check with Mac developers.

thanks again.

Mar 15, 2010 at 7:34 PM

One more question.

should I condsider changing this code if there are subfolders in a folder that i am about to zip and download?

Coordinator
Mar 15, 2010 at 7:58 PM
Edited Mar 15, 2010 at 8:20 PM

ok, let me ask you - what do you mean by "decompression does not work" ?

Another user has reported problems opening zip files on the mac, that are produced this way. I don't recommend reading the thread, because it is even more confusing to read it, than it was to participate in it, but here it is: (http://dotnetzip.codeplex.com/Thread/View.aspx?ThreadId=59740).  The working theory that I developed, but never confirmed, after that discussion, was that "the bit 3 option" in the zip file was causing a compatibility issue with Macintosh tools.

The "bit 3" is always turned on in a zipfile that you write to a non-seekable output stream, which is what Response.OutputStream is. 

The way to get a zip file without bit 3 is to write the zipfile to a seekable stream.  Two examples of this are:  a MemoryStream, or a FileStream (representing a filesystem file). 

This is worth a try.  If you use the   MemoryStream idea, then your code looks like this:

Private Sub ZipFolder(ByVal FolderToZip As String)
    Response.Clear()
    Response.BufferOutput = False

    Dim archiveName As String = _
        Path.GetFileName(FolderToZip) & "_" & (DateTime.Now.ToString("yyyyMMMdd_HHmmss")) & ".zip"

    Response.ContentType = "application/zip"
    Response.AddHeader("Content-Disposition", "filename=" & chr(34) & archiveName & chr(34))

    Using ms as New System.IO.MemoryStream()
        Using zip As ZipFile = New ZipFile()
            zip.AddDirectory(FolderToZip)
            '' save the zip fiel to a memory stream
            zip.Save(ms)
        End Using
        '' now copy the memory stream to the Response OutputStream
        ms.Position = 0
        dim b(1024) as Byte
        dim n as new Int32
        n=-1
        While (n <> 0)
            n = ms.Read(b,0,b.Length)
            If (n <> 0)
                Response.OutputStream.Write(b,0,n)
            End If
        End While
        Response.Close
    End Using
    Response.Close()
End Sub

In this case, the entire contents of the compressed zip will be placed into memory, before writing it out to Response.OutputStream.  This may or may not be acceptable to you, depending on how large the zip file is.

If you use the FileStream idea, then your code would look like this:

Private Sub ZipFolder(ByVal FolderToZip As String)
    Response.Clear()
    Response.BufferOutput = False

    Dim archiveName As String = _
        Path.GetFileName(FolderToZip) & "_" & (DateTime.Now.ToString("yyyyMMMdd_HHmmss")) & ".zip"

    Response.ContentType = "application/zip"
    Response.AddHeader("Content-Disposition", "filename=" & chr(34) & archiveName & chr(34))
    Dim tempfile As String = "c:\temp\" & archiveName
    Using zip As ZipFile = New ZipFile()
        zip.AddDirectory(FolderToZip)
        '' save the zip fiel to a memory stream
        zip.Save(tempfile)
    End Using
    ' open and read the file, and copy it to Response.OutputStream
    Using fs as System.IO.FileStream = System.IO.File.OpenRead(tempfile)
        dim b(1024) as Byte
        dim n as New Int32
        n=-1
        While (n <> 0)
            n = fs.Read(b,0,b.Length)
            If (n <> 0)
                Response.OutputStream.Write(b,0,n)
            End If
        End While
    End Using
    Response.Close
    System.IO.File.Delete(tempfile)
End Sub

Try one of those and see if it works for you.