framework - Crear archivo Zip desde mĂșltiples archivos de memoria en C#
save zip c# (8)
Esta función debería crear una matriz de bytes a partir de una secuencia de datos: he creado una interfaz simple para manejar archivos por simplicidad
public interface IHasDocumentProperties
{
byte[] Content { get; set; }
string Name { get; set; }
}
public void CreateZipFileContent(string filePath, IEnumerable<IHasDocumentProperties> fileInfos)
{
using (var memoryStream = new MemoryStream())
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach(var fileInfo in fileInfos)
{
var entry = zipArchive.CreateEntry(fileInfo.Name);
using (var entryStream = entry.Open())
{
entryStream.Write(fileInfo.Content, 0, fileInfo.Content.Length);
}
}
}
using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate, System.IO.FileAccess.Write))
{
memoryStream.CopyTo(fileStream);
}
}
¿Hay alguna manera de crear un archivo Zip que contenga varios archivos cuando los archivos están actualmente en la memoria? Los archivos que quiero guardar son en realidad solo texto y están almacenados en una clase de cadena en mi aplicación. Pero me gustaría guardar varios archivos en un solo archivo autónomo. Todos pueden estar en la raíz del archivo.
Sería bueno poder hacer esto usando SharpZipLib.
Tenga en cuenta que esta respuesta está desactualizada; desde .Net 4.5, la clase ZipArchive
permite comprimir archivos en la memoria. Ver la respuesta de johnny 5 a continuación para saber cómo usarlo.
También podría hacerlo de forma un poco diferente, utilizando un objeto Serializable para almacenar todas las cadenas
[Serializable]
public class MyStrings {
public string Foo { get; set; }
public string Bar { get; set; }
}
Luego, puede serializarlo en una secuencia para guardarlo.
Para ahorrar espacio, puede usar GZipStream (desde System.IO.Compression) para comprimirlo. (nota: GZip es compresión de flujo, no un archivo de múltiples archivos).
Eso es, por supuesto, si lo que necesita es guardar datos y no comprimir algunos archivos en un formato específico para otro software. Además, esto le permitirá guardar muchos más tipos de datos excepto cadenas.
Sí, puede usar SharpZipLib para hacer esto: cuando necesite suministrar una secuencia para escribir, use un MemoryStream
.
Use un StringReader para leer desde sus objetos de cadena y exponerlos como Stream s.
Eso debería facilitar el acceso a su código de creación de zip.
Usar SharpZipLib para esto parece bastante complicado. Esto es mucho más fácil en DotNetZip . En v1.9, el código se ve así:
using (ZipFile zip = new ZipFile())
{
zip.AddEntry("Readme.txt", stringContent1);
zip.AddEntry("readings/Data.csv", stringContent2);
zip.AddEntry("readings/Index.xml", stringContent3);
zip.Save("Archive1.zip");
}
El código anterior supone que stringContent {1,2,3} contiene los datos que se almacenarán en los archivos (o entradas) en el archivo zip. La primera entrada es "Readme.txt" y se almacena en el "directorio" de nivel superior en el archivo zip. Las siguientes dos entradas se almacenan en el directorio "lecturas" en el archivo zip.
Las cadenas están codificadas en la codificación predeterminada. Hay una sobrecarga de AddEntry (), que no se muestra aquí, que le permite especificar explícitamente la codificación que se usará.
Si tiene el contenido en una secuencia o matriz de bytes, no una cadena, hay sobrecargas para AddEntry () que aceptan esos tipos. También hay sobrecargas que aceptan un delegado de escritura, un método tuyo que se invoca para escribir datos en el zip. Esto funciona para guardar fácilmente un DataSet en un archivo zip, por ejemplo.
DotNetZip es gratuito y de código abierto.
Utilice ZipEntry
y PutNextEntry()
para esto. A continuación, se muestra cómo hacerlo para un archivo, pero para un objeto en memoria solo use un MemoryStream
FileStream fZip = File.Create(compressedOutputFile);
ZipOutputStream zipOStream = new ZipOutputStream(fZip);
foreach (FileInfo fi in allfiles)
{
ZipEntry entry = new ZipEntry((fi.Name));
zipOStream.PutNextEntry(entry);
FileStream fs = File.OpenRead(fi.FullName);
try
{
byte[] transferBuffer[1024];
do
{
bytesRead = fs.Read(transferBuffer, 0, transferBuffer.Length);
zipOStream.Write(transferBuffer, 0, bytesRead);
}
while (bytesRead > 0);
}
finally
{
fs.Close();
}
}
zipOStream.Finish();
zipOStream.Close();
Me encuentro con este problema, utilizando el ejemplo de MSDN que creé esta clase:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Packaging;
using System.IO;
public class ZipSticle
{
Package package;
public ZipSticle(Stream s)
{
package = ZipPackage.Open(s, FileMode.Create);
}
public void Add(Stream stream, string Name)
{
Uri partUriDocument = PackUriHelper.CreatePartUri(new Uri(Name, UriKind.Relative));
PackagePart packagePartDocument = package.CreatePart(partUriDocument, "");
CopyStream(stream, packagePartDocument.GetStream());
stream.Close();
}
private static void CopyStream(Stream source, Stream target)
{
const int bufSize = 0x1000;
byte[] buf = new byte[bufSize];
int bytesRead = 0;
while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
target.Write(buf, 0, bytesRead);
}
public void Close()
{
package.Close();
}
}
Puede usarlo así:
FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create);
ZipSticle zip = new ZipSticle(str);
zip.Add(File.OpenRead("C:/Users/C0BRA/SimpleFile.txt"), "Some directory/SimpleFile.txt");
zip.Add(File.OpenRead("C:/Users/C0BRA/Hurp.derp"), "hurp.Derp");
zip.Close();
str.Close();
Puede pasar un MemoryStream
(o cualquier Stream
) a ZipSticle.Add
como:
FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create);
ZipSticle zip = new ZipSticle(str);
byte[] fileinmem = new byte[1000];
// Do stuff to FileInMemory
MemoryStream memstr = new MemoryStream(fileinmem);
zip.Add(memstr, "Some directory/SimpleFile.txt");
memstr.Close();
zip.Close();
str.Close();
Estaba utilizando la respuesta de Cheeso agregando MemoryStream
como fuente de los diferentes archivos de Excel. Cuando descargué el archivo comprimido, los archivos no tenían nada en ellos. Esta podría ser la forma en que estábamos tratando de crear y descargar un archivo a través de AJAX.
Para obtener los contenidos de los diferentes archivos de Excel para ser incluidos en el Zip, tuve que agregar cada uno de los archivos como un byte[]
.
using (var memoryStream = new MemoryStream())
using (var zip = new ZipFile())
{
zip.AddEntry("Excel File 1.xlsx", excelFileStream1.ToArray());
zip.AddEntry("Excel File 2.xlsx", excelFileStream2.ToArray());
// Keep the file off of disk, and in memory.
zip.Save(memoryStream);
}