Solución:
Puede utilizar el controlador File
método para devolver un archivo, como:
public ActionResult Download()
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Directories/hello"));
zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
return File(Server.MapPath("~/Directories/hello/sample.zip"),
"application/zip", "sample.zip");
}
}
Si no es necesario almacenar el archivo zip de otro modo, no es necesario escribirlo en un archivo en el servidor:
public ActionResult Download()
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Directories/hello"));
MemoryStream output = new MemoryStream();
zip.Save(output);
return File(output.ToArray(), "application/zip", "sample.zip");
}
}
En primer lugar, considere una forma sin crear ningún archivo en el disco del servidor. Mala práctica. Recomiendo crear un archivo y comprimirlo en la memoria. Espero que encuentre útil mi ejemplo a continuación.
/// <summary>
/// Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the ZIP container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
var zipEntry = zip.CreateEntry(fileName);
using (var writer = new StreamWriter(zipEntry.Open()))
{
originalFileStream.WriteTo(writer.BaseStream);
}
return zipStream.ToArray();
}
}
}
/// <summary>
/// Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
"application/zip",
"sample.zip");
}
Notas sobre el código anterior:
- Pasando un
MemoryStream
La instancia requiere verificaciones de que esté abierta, válida, etc. Las omití. Prefiero pasar una matriz de bytes del contenido del archivo en lugar de unaMemoryStream
instancia para hacer el código más robusto, pero sería demasiado para este ejemplo. - No muestra cómo crear un contexto requerido (su archivo) en la memoria. Me referiría a la clase MemoryStream para obtener instrucciones.
solo una solución a la solución de Klaus: (como no puedo agregar un comentario, tengo que agregar otra respuesta)
La solución es excelente, pero para mí dio un archivo zip dañado y me di cuenta de que se debe a que la devolución es antes de finalizar el objeto zip, por lo que no cerró el zip y dio como resultado un zip dañado.
así que para solucionarlo, solo tenemos que mover la línea de retorno después de usar el bloque zip para que funcione. el resultado final es:
/// <summary>
/// Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the ZIP container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
var zipEntry = zip.CreateEntry(fileName);
using (var writer = new StreamWriter(zipEntry.Open()))
{
originalFileStream.WriteTo(writer.BaseStream);
}
}
return zipStream.ToArray();
}
}
/// <summary>
/// Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
"application/zip",
"sample.zip");
}