Créer une archive Zip à partir de plusieurs fichiers en mémoire en C #

Est-il possible de créer une archive Zip contenant plusieurs fichiers alors que les fichiers sont actuellement en mémoire? Les fichiers que je veux enregistrer ne sont en réalité que du texte et sont stockés dans une classe de chaîne dans mon application. Mais je voudrais enregistrer plusieurs fichiers dans une seule archive autonome. Ils peuvent tous être à la racine de l’archive.

Ce serait bien de pouvoir le faire avec SharpZipLib.

Utilisez ZipEntry et PutNextEntry() pour cela. Ce qui suit montre comment procéder pour un fichier, mais pour un object en mémoire, utilisez simplement 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(); 

Utiliser SharpZipLib pour cela semble assez compliqué. C’est tellement plus facile avec DotNetZip . Dans la v1.9, le code ressemble à ceci:

 using (ZipFile zip = new ZipFile()) { zip.AddEntry("Readme.txt", ssortingngContent1); zip.AddEntry("readings/Data.csv", ssortingngContent2); zip.AddEntry("readings/Index.xml", ssortingngContent3); zip.Save("Archive1.zip"); } 

Le code ci-dessus suppose que ssortingngContent {1,2,3} contient les données à stocker dans les fichiers (ou entrées) de l’archive zip. La première entrée est “Readme.txt” et il est stocké dans le répertoire “Répertoire” de niveau supérieur de l’archive zip. Les deux entrées suivantes sont stockées dans le répertoire “readings” de l’archive zip.

Les chaînes sont codées dans le codage par défaut. Il existe une surcharge de AddEntry (), non illustrée ici, qui vous permet de spécifier explicitement le codage à utiliser.

Si vous avez le contenu dans un stream ou un tableau d’octets, et non une chaîne, il existe des surcharges pour AddEntry () qui acceptent ces types. Il existe également des surcharges qui acceptent un délégué Write, une de vos méthodes appelée pour écrire des données dans le zip. Cela fonctionne pour enregistrer facilement un DataSet dans un fichier zip, par exemple.

DotNetZip est gratuit et open source.

Oui, vous pouvez utiliser SharpZipLib pour cela. Lorsque vous devez fournir un stream pour écrire, utilisez un MemoryStream .

Je rencontre ce problème en utilisant l’exemple MSDN que j’ai créé cette classe:

 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, ssortingng 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(); } } 

Vous pouvez ensuite l’utiliser comme ceci:

 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(); 

Vous pouvez transmettre un MemoryStream (ou n’importe quel Stream ) à ZipSticle.Add tel que:

 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(); 

Notez que cette réponse est obsolète. Depuis .Net 4.5, la classe ZipArchive permet de compresser des fichiers en mémoire. Voir la réponse de Johnny 5 ci-dessous pour savoir comment l’utiliser.


Vous pouvez également le faire un peu différemment, en utilisant un object Serializable pour stocker toutes les chaînes.

 [Serializable] public class MySsortingngs { public ssortingng Foo { get; set; } public ssortingng Bar { get; set; } } 

Ensuite, vous pouvez le sérialiser dans un stream pour le sauvegarder.
Pour économiser de l’espace, vous pouvez utiliser GZipStream (From System.IO.Compression) pour le compresser. (Remarque: GZip est une compression de stream, pas une archive de plusieurs fichiers).

Bien sûr, si vous avez réellement besoin de sauvegarder des données et non de compresser quelques fichiers dans un format spécifique pour un autre logiciel. En outre, cela vous permettrait d’enregistrer beaucoup plus de types de données, à l’exception des chaînes.

Cette fonction devrait créer un tableau d’octets à partir d’un stream de données: j’ai créé une interface simple pour gérer les fichiers pour plus de simplicité

 public interface IHasDocumentProperties { byte[] Content { get; set; } ssortingng Name { get; set; } } public void CreateZipFileContent(ssortingng filePath, IEnumerable 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); } } 

J’utilisais la réponse de Cheeso en ajoutant MemoryStream s en tant que source des différents fichiers Excel. Lorsque j’ai téléchargé le zip, les fichiers ne contenaient rien. C’est peut-être ainsi que nous essayions de créer et de télécharger un fichier via AJAX.

Pour obtenir le contenu des différents fichiers Excel à inclure dans le zip, je devais append chacun des fichiers sous forme d’ 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); } 

Utilisez un SsortingngReader pour lire à partir de vos objects chaîne et les exposer sous forme de stream.

Cela devrait faciliter leur intégration dans votre code de construction zip.