Home Forums .NET libraries Xceed Zip & Real-Time Zip for .NET real time zip to memory stream (asp.net) returns 0 byte size files in zip

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • User (Old forums)
    Member
    Post count: 23064
    #19985 |

    Hi there,

    My first try with real time zip which we want to use on an asp.net site. We are currently using another component but the time from user initiating a multifile zip download to starting the download i.e. the add file/compression stage, is far too long. I’m hoping that zip on the fly will cut this time dramatically.

    I’ve adapted the code in your help files to use a memorystream, but once downloaded the zip file contains the correct number & names of the files, but each is 0 bytes in length.

    Could someone comment on the code below and point out where I could be going wrong. Assume that the source files are valid and all permissions are correct.

    Xceed.Zip.ReaderWriter.Licenser.LicenseKey =

    “trial licence key here”

    ‘The target Zip archive

    Using memStream As New MemoryStream()

    ‘Create the ZipWriter object around the stream.

    Dim zipWriter1 As New Xceed.Zip.ReaderWriter.ZipWriter(memStream)

    ‘The source directory

    Dim directoryInfo As New DirectoryInfo(“C:\files\”)

    If directoryInfo.Exists Then

    ‘Get files in the current directory and all subdirectories.

    Dim files As FileInfo() = directoryInfo.GetFiles(“*.*”, SearchOption.TopDirectoryOnly)

    For Each file As FileInfo In files

    ‘Create ZipItemLocalHeader for current item and write to archive.

    Dim zipItemLocalHeader1 As New ZipItemLocalHeader(file.Name)

    zipWriter1.WriteItemLocalHeader(zipItemLocalHeader1)

    Dim buffer As Byte() = New Byte(1023) {}

    Dim read As Integer = 0

    Using fs As FileStream = file.OpenRead()

    ‘Read the current item’s data

    Do While (read = fs.Read(buffer, 0, buffer.Length)) <> 0

    ‘Write the current item’s data to the Zip archive

    zipWriter1.WriteItemData(buffer, 0, read)

    Loop

    End Using

    Next file

    ‘Close the Zip archive. Writes the archive’s central header.

    zipWriter1.CloseZipFile()

    ‘Convert the memory stream to an array of bytes.

    Dim byteArray As Byte() = memStream.ToArray()

    Response.Clear()

    Response.ContentType =

    “application/x-zip-compressed”

    Response.AddHeader(

    “Content-Disposition”, “attachment;filename=my_archive.zip”)

    Response.AppendHeader(

    “Content-Length”, byteArray.Length.ToString())

    Response.BinaryWrite(byteArray)

    Response.End()

    End If

    End Using

    Imported from legacy forums. Posted by Sean (had 4577 views)

    User (Old forums)
    Member
    Post count: 23064

    This code:
      ‘Read the current item’s data
      Do While (read = fs.Read(buffer, 0, buffer.Length)) <> 0
          ‘Write the current item’s data to the Zip archive
          zipWriter1.WriteItemData(buffer, 0, read)
      Loop
    is not valid (it looks like it’s badly translated C# code) because the line
      Do While (read = fs.Read(buffer, 0, buffer.Length)) <> 0
    is not valid and results in the Do loop never being entered

    It should be something like:

      ‘Read the current item’s data
      read = fs.Read(buffer, 0, buffer.Length)
      Do While (read <> 0)
          ‘Write the current item’s data to the Zip archive
          zipWriter1.WriteItemData(buffer, 0, read)
          read = fs.Read(buffer, 0, buffer.Length)
      Loop

    Imported from legacy forums. Posted by Chris (had 651 views)

    User (Old forums)
    Member
    Post count: 23064

    Hi Chris,

    That VB code was pasted straight from the real time zip help file examples!

    Your amend works – the zip files now contain files correctly sized, but the time taken before download dialogue appears (i.e. the addfile/compress stage) is still as long as before. Its as if the real time aspect is not happening.

    Am I mistaken that the download dialogue should appear early – after the first file added almost? Or would this not work for a web download as the server/client want to know total bytes before starting anything.

    The help files focus only on winforms/console apps which might be a hint that real time zip not suitable for asp.net apps?

     thanks

    Sean

    Imported from legacy forums. Posted by Sean (had 552 views)

    User (Old forums)
    Member
    Post count: 23064

    The problem using the code as-is in asp.net is that it first loads and compresses the file (the Do While loop) then writes the compressed data to the Response.

    Try this code instead (I did it on a 500Mb file and received a smaller compressed file – which started downloading within seconds)

    ‘ Prepare the response
    Response.Clear()
    Response.ContentType =
    “application/x-zip-compressed”
    Response.AddHeader(“Content-Disposition”, “attachment;filename=my_archive.zip”)
    ‘Create the ZipWriter object around the response stream.
    Dim zipWriter1 As New Xceed.Zip.ReaderWriter.ZipWriter(Response.OutputStream)

    ‘The source directory
    Dim directoryInfo As New DirectoryInfo(“E:\files\”)
    If directoryInfo.Exists Then
     ‘Get files in the current directory and all subdirectories.
     Dim files As FileInfo() = directoryInfo.GetFiles(“*.*”, SearchOption.TopDirectoryOnly)
     
    For Each file As FileInfo In files
     
    ‘Create ZipItemLocalHeader for current item and write to archive.
     
    Dim zipItemLocalHeader1 As New ZipItemLocalHeader(file.Name)
      zipWriter1.WriteItemLocalHeader(zipItemLocalHeader1)
     
    ‘Start streaming file to response via compressing writer
     
    Dim buffer As Byte() = New Byte(1023) {}
      Dim read As Integer = 0
     
    Using fs As FileStream = file.OpenRead()
       
    ‘Read the current item’s data
      
    read = fs.Read(buffer, 0, buffer.Length)
      
    Do While (read <> 0)
       
    ‘Write the current item’s data to the Zip archive
       
    zipWriter1.WriteItemData(buffer, 0, read)
       
    ‘Write that data to the response straight away
       
    Response.Flush()
        read = fs.Read(buffer, 0, buffer.Length)
      
    Loop
     
    End Using
     
    Next file
     
    ‘Close the Zip archive. 
     
    zipWriter1.CloseZipFile()
     Response.Flush()
     Response.End()
    End If

    You will probably want to use a bigger buffer and include checks to see if the client is still connected (and stop compressing the file if no-one is listening), etc, but it should give you the bare bones of a solution

    I hope it helps

    Chris

    Imported from legacy forums. Posted by Chris (had 600 views)

    User (Old forums)
    Member
    Post count: 23064

    Hi Chris,

    this works exactly as the original code promised – thanks for this.

    I just need to get my head around trying to give the user an earlier indication of expected download time as there is no total size to give the browser progress info.

     Regarding checking for client still connected is the best way to poll

    HttpContext.Current.Response.IsClientConnected

    within the Do While loop and break out if not. Is this a robust way of handling a client disconnect?

    Thanks again for the pointers

    regards

    SeanR

    Imported from legacy forums. Posted by Sean (had 623 views)

    User (Old forums)
    Member
    Post count: 23064

    No problem Sean

    Regarding total size – unfortunately you don’t really know it until the file has been fully compressed – which will be only one buffer full away from being complete.

    Perhaps the ByteProgression event may help somehow (I’m not sure how you could use it with asp.net, but I’ve seen other browser progress indicators so it might be possible mixing a separate request and browser window with some AJAX)

    And yes – Response.IsClientConnected basically checks if the browser is connected. I’m not sure how chatty it is though, so you may want to only check it every nth loop rather than every loop

    Chris

    Imported from legacy forums. Posted by Chris (had 3335 views)

Viewing 6 posts - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.