descomprimir - ziparchive c#
Creando archivo Zip desde la transmisión y descargándolo (8)
Tengo un DataTable que quiero convertir a xml y luego comprimirlo, usando DotNetZip. finalmente el usuario puede descargarlo a través de la página web de Asp.Net. Mi código a continuación
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();
el archivo xml en el archivo zip está vacío.
¿Has intentado lavar la corriente antes de comprimir?
dt.WriteXml(stream);
stream.Flush();
ZipFile zipFile = new ZipFile();
¿Por qué no cerraste el MemoryStream, lo incluiría en una cláusula de using
, lo mismo podría decirse de zipFile
? También supongo que dt
es una DataTable ... poner en error la comprobación para ver si hay filas, ver el código a continuación ...
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...
Editar: habiendo mirado esto de nuevo, y dándome cuenta de que Ionic.Ziplib de Codeplex se usó, cambié el código ligeramente, en lugar de zipFile.Save(Response.OutputStream);
Utilicé zipFile.Save(stream);
usar la instancia de la stream
de la clase MemoryStream
y escribirla usando Response.Write(stream);
.
Editar # 2: Gracias a Cheeso + Mikael por señalar la falla obvia: me perdí a una milla de distancia y no entendí su comentario hasta que me di cuenta de que la transmisión estaba al final ...
2 cosas. Primero, si conserva el diseño del código que tiene, debe realizar una Búsqueda () en el MemoryStream antes de escribirlo en la entrada.
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);
}
Incluso si mantiene este diseño, sugeriría una cláusula using (), como lo he mostrado, y como se describe en todos los ejemplos de DotNetZip , en lugar de llamar a Dispose (). La cláusula using () es más confiable ante fallas.
Ahora se puede preguntar, ¿por qué es necesario buscar en el MemoryStream antes de llamar a AddEntry ()? El motivo es que AddEntry () está diseñado para admitir a los llamantes que pasan una transmisión donde la posición es importante. En ese caso, la persona que llama necesita que los datos de entrada se lean de la transmisión, usando la posición actual de la transmisión . AddEntry () lo admite. Por lo tanto, establezca la posición en la secuencia antes de llamar AddEntry ().
Pero, la mejor opción es modificar su código para usar la sobrecarga de AddEntry () que acepta un WriteDelegate . Fue diseñado específicamente para agregar conjuntos de datos en archivos zip. Su código original escribe el conjunto de datos en una secuencia de memoria, luego busca en la secuencia y escribe el contenido de la secuencia en el archivo zip. Es más rápido y más fácil si escribe los datos una vez, que es lo que WriteDelegate le permite hacer. El código se ve así:
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);
}
Esto escribe el conjunto de datos directamente en la secuencia comprimida en el archivo zip. ¡Muy eficiente! Sin doble buffer. El delegado anónimo se llama en el momento de ZipFile.Save (). Solo se realiza una escritura (+ compresión).
Agregue un encabezado ContentType:
Response.ContentType = "application/zip";
esto permitirá que los navegadores detecten lo que estás enviando.
Creando un archivo zip desde la transmisión y descargándolo. A continuación está el código.
FileStream stream=File.OpenRead(@"D:/FileDownLoad/DeskTop/1.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());
De acuerdo. No parece que lleguemos muy lejos, así que debes comenzar a depurar esto un poco más.
Actualiza tu código para hacer lo siguiente:
dt.WriteXml(stream);
stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes("c:/test.xml", stream.GetBuffer());
Vea si tiene un archivo XML válido. Si lo haces, entonces sigue haciendo lo mismo con tu ZipFile. Guárdelo en un archivo local. Vea si está allí, tiene su archivo xml y su archivo xml tiene contenido.
Si eso funciona, intente enviar solo la secuencia de la memoria como respuesta, vea si eso funciona.
Debería poder seguir el problema más allá.
Este código lo ayudará a descargar un archivo de la transmisión.
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);
}
}
Espacios de nombres necesarios:
using System.IO.Compression;
using System.IO.Compression.ZipArchive;
Verifique nuevamente la transmisión que está regresando también. En tu ejemplo a continuación
zipFile.Save(Response.OutputStream);
Response.Write(zipstream);
zipFile.Dispose();
Está guardando el zipFile en su flujo de respuesta utilizando el método Save, pero luego también está llamando a Response.Write () con una variable zipstream. ¿Qué es zipstream? Verifique que no sea una transmisión vacía también.