Création D'un fichier Zip à partir du flux et téléchargement

j'ai un DataTable que je veux convertir en xml puis le zip, en utilisant DotNetZip. enfin l'utilisateur peut le télécharger via Asp.Net page web. Mon code ci-dessous

    dt.TableName = "Declaration";

    MemoryStream stream = new MemoryStream();
    dt.WriteXml(stream);

    ZipFile zipFile = new ZipFile();
    zipFile.AddEntry("Report.xml", "", stream);
    Response.ClearContent();
    Response.ClearHeaders();
    Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");

    zipFile.Save(Response.OutputStream);
    //Response.Write(zipstream);
    zipFile.Dispose();

le fichier xml dans le fichier zip est vide.

44
demandé sur Navid Farhadi 2010-02-15 16:29:07

8 réponses

2 choses. Tout d'abord, si vous gardez la conception de code que vous avez, vous devez effectuer un Seek() sur le MemoryStream avant de l'écrire dans l'entrée.

dt.TableName = "Declaration"; 

MemoryStream stream = new MemoryStream(); 
dt.WriteXml(stream); 
stream.Seek(0,SeekOrigin.Begin);   // <-- must do this after writing the stream!

using (ZipFile zipFile = new ZipFile())
{
  zipFile.AddEntry("Report.xml", "", stream); 
  Response.ClearContent(); 
  Response.ClearHeaders(); 
  Response.AppendHeader("content-disposition", "attachment; filename=Report.zip"); 

  zipFile.Save(Response.OutputStream); 
}

même si vous conservez cette conception, je suggérerais une clause d'utilisation (), comme je l'ai montré, et comme décrit dans tous les DotNetZip examples, au lieu d'appeler dispose(). La clause using () est plus fiable en cas de défaillance.

Maintenant vous pouvez vous demander, pourquoi est-il nécessaire de chercher dans le MemoryStream avant D'appeler AddEntry ()? La raison est, AddEntry () est conçu pour soutenir les appelants qui passent un flux où le poste est important. Dans ce cas, l'appelant a besoin que les données d'entrée soient lues à partir du flux,en utilisant la position actuelle du flux. AddEntry () supporte cela. Par conséquent, définissez la position dans le flux avant D'appeler AddEntry().

Mais, la meilleure option est de modifier votre code pour utiliser le surcharge de AddEntry() qui accepte un WriteDelegate. Il a été conçu spécifiquement pour ajouter des ensembles de données dans les fichiers zip. Votre code original écrit l'ensemble de données dans un flux de mémoire, puis cherche sur le flux, et écrit le contenu du flux dans le zip. C'est plus rapide et plus facile si vous écrivez les données une fois, ce qui est ce que le WriteDelegate vous permet de faire. Le code ressemble à ceci:

dt.TableName = "Declaration"; 
Response.ClearContent(); 
Response.ClearHeaders(); 
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip"); 

using(Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
    zipFile.AddEntry("Report.xml", (name,stream) => dt.WriteXml(stream) );
    zipFile.Save(Response.OutputStream); 
}

ceci écrit l'ensemble de données directement dans le flux compressé dans le zipfile. Très efficace! Pas de double tampon. Le délégué anonyme est appelé au moment de ZipFile.Enregistrer.)( Une seule écriture (+compresse) est effectuée.

67
répondu Cheeso 2011-06-17 12:50:50

pourquoi n'avez-vous pas fermé le MemoryStream, Je l'envelopperais dans un using l'article, la même chose pourrait être dit pour zipFile? Aussi dt je suppose que C'est un Dattable...mis dans la vérification d'erreur pour voir s'il y a des lignes, voir le code ci-dessous...

    dt.TableName = "Declaration"; 

    if (dt.Rows != null && dt.Rows.Count >= 1){
      using (MemoryStream stream = new MemoryStream()){
         dt.WriteXml(stream); 

         // Thanks Cheeso/Mikael
         stream.Seek(0, SeekOrigin.Begin);
         //

         using (ZipFile zipFile = new ZipFile()){
             zipFile.AddEntry("Report.xml", "", stream); 
             Response.ClearContent(); 
             Response.ClearHeaders(); 
             Response.AppendHeader("content-disposition", "attachment; filename=Report.zip"); 

             //zipFile.Save(Response.OutputStream); 
             zipFile.Save(stream);

             // Commented this out
             /*
               Response.Write(zipstream); // <----- Where did that come from?
             */
          }
          Response.Write(stream);
       } 
    }
    // No rows...don't bother...

Edit: ayant revu cela, et se rendant compte que Ionique.Ziplib à partir de Codeplex a été utilisé, j'ai changé le code légèrement, au lieu de zipFile.Save(Response.OutputStream); j'ai utilisé zipFile.Save(stream);stream exemple MemoryStream de la classe et de l'écrire à l'aide de Response.Write(stream);.

Edit#2: merci à Cheeso+ Mikael pour avoir souligné le défaut évident - je l'ai manqué à un mile et n'ai pas compris leur commentaire jusqu'à ce que je me rende compte que le ruisseau était à la fin...

5
répondu t0mm13b 2018-06-05 23:19:43

avez-vous essayé de tirer la chasse d'eau avant de fermer?

dt.WriteXml(stream);
stream.Flush();
ZipFile zipFile = new ZipFile();
1
répondu jmservera 2010-02-15 14:13:15

Ok. Il ne semble pas que nous allons très loin ici, donc vous devez commencer à déboguer un peu plus.

mise à Jour vous êtes le code suivant:

dt.WriteXml(stream);
stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes("c:\test.xml", stream.GetBuffer());

Voir si vous avez un fichier XML valide. Si vous le faites, puis passer à faire la même chose avec votre ZipFile. Enregistrer dans un fichier local. Voir s'il est là, a votre fichier xml et votre fichier xml a du contenu en elle.

si cela fonctionne, essayez de renvoyer juste le flux de mémoire comme réponse, voir si cela travail.

Vous devriez alors être en mesure de localiser le problème plus.

1
répondu Ian 2010-02-15 15:12:24

Ajouter un en-tête ContentType:

Response.ContentType = "application/zip";

cela permettra aux navigateurs pour détecter ce que vous envoyez.

0
répondu Mikael Svenson 2010-02-15 13:46:08

vérifiez le flux que vous retournez aussi. Dans l'exemple ci-dessous

zipFile.Save(Response.OutputStream);
Response.Write(zipstream);
zipFile.Dispose();

vous sauvegardez le fichier zip à votre flux de réponse en utilisant la méthode Save, mais ensuite vous appelez aussi Response.Write () avec une variable zipstream. Qu'est-ce que zipstream? Vérifiez que ce n'est pas un flux vide aussi.

0
répondu Ian 2010-02-15 14:21:13

Création d'un fichier zip à partir de flux et de le télécharger. Ci-dessous est le code.

FileStream stream=File.OpenRead(@"D:\FileDownLoad\DeskTop.txt");
MemoryStream MS=new MemoryStream();

ZipOutputStream zipOutputStream = new ZipOutputStream(MS);
zipOutputStream.SetLevel(9);
ZipEntry entry = new ZipEntry("1.txt");
zipOutputStream.PutNextEntry(entry);

byte[] buffer = new byte[stream.Length];
int byteRead = 0;

while ((byteRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
    zipOutputStream.Write(buffer, 0, byteRead);

    zipOutputStream.IsStreamOwner = false;
    stream.Close();
    zipOutputStream.Close();
    MS.Position = 0;

    Response.ContentType = "application/application/octet-stream";
    Response.AppendHeader("content-disposition", "attachment; filename=\"Download.zip\"");
    Response.BinaryWrite(MS.ToArray());
0
répondu Sheo Dayal Singh 2016-09-04 18:58:04

ce code vous aidera à télécharger un fichier depuis stream.

using (var outStream = new MemoryStream())
{
    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
        var fileInArchive = archive.CreateEntry("FileName.pdf", CompressionLevel.Optimal);
        using (var entryStream = fileInArchive.Open())
        using (WebResponse response = req.GetResponse())
        {
            using (var fileToCompressStream = response.GetResponseStream())
            {
                fileToCompressStream.CopyTo(entryStream);
            }
        }                       
    }
    using (var fileStream = new FileStream(@"D:\test.zip", FileMode.Create))
    {
        outStream.Seek(0, SeekOrigin.Begin);
        outStream.CopyTo(fileStream);
    }
}

les espaces de noms nécessaires:

using System.IO.Compression;
using System.IO.Compression.ZipArchive;
0
répondu Skull 2018-04-22 12:37:42