Créer une archive ZIP à plat
Votre archive zip peut contenir d’autres archives zip. On souhaitera peut-être extraire le contenu de l’archive zip imbriquée dans l’archive parent pour obtenir une structure plate.
Structure actuelle des archives
outer.zip ├first.txt ├inner.zip │ ├game.exe │ └subitem.bin └picture.gif
Structure d'archive souhaitée
flatten.zip ├first.txt ├picture.gif ├game.exe └subitem.bin
Si vous n’êtes pas familier avec Aspose.Zip, lisez d’abord comment extraire l’archive zip.
Explication générale
Tout d’abord, nous devons lister toutes les entrées de l’archive. Les entrées régulières doivent être conservées telles quelles, il ne faut même pas les décompresser. Les entrées qui sont elles-mêmes des archives doivent être extraites de la mémoire et supprimées de l’archive externe. Leur contenu doit être inclus dans l’archive principale.
Détection des entrées qui sont des archives
Décidons quelles entrées sont elles-mêmes des archives. Nous pouvons comprendre cela par extension du nom de l’entrée. Plus tard, nous supprimerons ces entrées de l’archive principale, conservez donc ces entrées dans une liste.
1if (entry.Name.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) {
2 entriesToDelete.Add(entry);
3 ...
4}
Extraction du contenu de l’entrée en mémoire
Aspose.Zip permet d’extraire le contenu d’une entrée zip dans n’importe quel flux inscriptible, pas seulement dans un fichier. Ainsi, nous pouvons extraire une archive imbriquée dans un flux mémoire.
Attention : la mémoire virtuelle doit être suffisamment grande pour conserver tout le contenu extrait.
1MemoryStream innerCompressed = new MemoryStream();
2entry.Open().CopyTo(innerCompressed);
Après ce flux innerCompressed contient l’archive interne elle-même. Le Constructeur d’archive permet de décompresser le flux fourni. Nous pouvons donc l’extraire également :
1Archive inner = new Archive(innerCompressed);
Hors entrées
Nous pouvons supprimer une entrée de l’archive zip avec méthode particulière.
1foreach (ArchiveEntry e in entriesToDelete) { outer.DeleteEntry(e); }
Mettez tout cela ensemble
Voici l’algorithme complet.
1 using (Archive outer = new Archive("outer.zip"))
2 {
3 List<ArchiveEntry> entriesToDelete = new List<ArchiveEntry>();
4 List<string> namesToInsert = new List<string>();
5 List<MemoryStream> contentToInsert = new List<MemoryStream>();
6
7 foreach (ArchiveEntry entry in outer.Entries)
8 {
9 if (entry.Name.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) // Find an entry which is an archive itself
10 {
11 entriesToDelete.Add(entry); // Keep reference to the entry in order to remove it from the archive later
12 MemoryStream innerCompressed = new MemoryStream();
13 entry.Open().CopyTo(innerCompressed); //This extracts the entry to a memory stream
14
15 using (Archive inner = new Archive(innerCompressed)) // We know that content of the entry is an zip archive so we may extract
16 {
17 foreach (ArchiveEntry ie in inner.Entries) // Loop over entries of inner archive
18 {
19 namesToInsert.Add(ie.Name); // Keep the name of inner entry.
20 MemoryStream content = new MemoryStream();
21 ie.Open().CopyTo(content);
22 contentToInsert.Add(content); // Keep the content of inner entry.
23 }
24 }
25 }
26 }
27
28 foreach (ArchiveEntry e in entriesToDelete)
29 outer.DeleteEntry(e); // Delete all the entries which are archives itself
30
31 for (int i = 0; i < namesToInsert.Count; i++)
32 outer.CreateEntry(namesToInsert[i], contentToInsert[i]); // Adds entries which were entries of inner archives
33
34 outer.Save("flatten.zip");
35 }