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.
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.
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...
avez-vous essayé de tirer la chasse d'eau avant de fermer?
dt.WriteXml(stream);
stream.Flush();
ZipFile zipFile = new ZipFile();
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.
Ajouter un en-tête ContentType:
Response.ContentType = "application/zip";
cela permettra aux navigateurs pour détecter ce que vous envoyez.
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.
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());
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;