-->

Create and stream image archive zip file for downl

2020-06-06 05:36发布

问题:

I am using the beloved DotNetZip archiving library in MVC3 to generate a Zip file on the fly which contains .png images from binaries stored in a database. I then stream the generated Zip file out for the user to download. (I validate image data prior to saving to to the database, so you can assume that all image data is valid).

public ActionResult PictureExport()
      {
           IEnumerable<UserPicture> userPictures = db.UserPicture.ToList();
           //"db" is a DataContext and UserPicture is the model used for uploaded pictures.
           DateTime today = DateTime.Now;
           string fileName = "attachment;filename=AllUploadedPicturesAsOf:" + today.ToString() + ".zip";
           this.Response.Clear();
           this.Response.ContentType = "application/zip";
           this.Response.AddHeader("Content-Disposition", fileName);

           using (ZipFile zipFile = new ZipFile())
             {
               using (MemoryStream stream = new MemoryStream())
                {
                 foreach (UserPicture userPicture in userPictures)
                  {
                     stream.Seek(0, SeekOrigin.Begin);
                     string pictureName = userPicture.Name+ ".png";
                     using (MemoryStream tempstream = new MemoryStream())
                     {
                        Image userImage = //method that returns Drawing.Image from byte[];
                        userImage.Save(tempstream, ImageFormat.Png);
                        tempstream.Seek(0, SeekOrigin.Begin);
                        stream.Seek(0, SeekOrigin.Begin);
                        tempstream.WriteTo(stream);
                     }

                     zipFile.AddEntry(pictureName, stream);
                 }

                zipFile.Save(Response.OutputStream);
              }

           }

        this.Response.End();
        return RedirectToAction("Home");
      }

This code will work for uploading and exporting ONE (1) image. However, after uploading more than one image to the database and then attempting to export them all, the Zip file that is generated will only contain the data of the most recent uploaded image. All the other image NAMES will appear in the zip file, but their file size will be 0 and they are simply empty files.

I'm guessing my issue has to do with the MemoryStreams (or that I'm missing something simple), but as far as I can tell by stepping through the code, the images are being pulled from the database and are being added to the zip file successfully...

回答1:

Your calls to stream.Seek(0, SeekOrigin.Begin) are causing the contents of the stream to be overwritten each iteration with the most recent image data. Try this instead:

using (ZipFile zipFile = new ZipFile())
{
    foreach (var userPicture in userPictures)
    {
        string pictureName = userPicture.Name + ".png";
        using (MemoryStream tempstream = new MemoryStream())
        {
            Image userImage = //method that returns Drawing.Image from byte[];   
            userImage.Save(tempstream, ImageFormat.Png);  
            tempstream.Seek(0, SeekOrigin.Begin);
            byte[] imageData = new byte[tempstream.Length];
            tempstream.Read(imageData, 0, imageData.Length);
            zipFile.AddEntry(pictureName, imageData);
        }
    }

    zipFile.Save(Response.OutputStream);
}