Comment créer une archive ZIP plate
Votre archive zip peut contenir d’autres archives zip. On peut vouloir extraire le contenu de l’archive zip imbriquée dans l’archive mère pour obtenir une structure plate.
Structure actuelle de l'archive
outer.zip ├first.txt ├inner.zip │ ├game.exe │ └subitem.bin └picture.gif
Structure des archives 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 une 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, nous ne devons 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éterminons quelles entrées sont des archives. Nous pouvons le découvrir par l’extension du nom de l’entrée. Plus tard, nous supprimerons ces entrées de l’archive principale, donc gardons ces entrées dans une liste.
1if(entry.getName().toLowerCase(Locale.ROOT).endsWith(".zip")) {
2 entriesToDelete.add(entry) ;
3 ...
4}
Extraction du contenu de l’entrée dans la mémoire
Aspose.Zip permet d’extraire le contenu d’une entrée zip dans n’importe quel flux accessible en écriture, et pas seulement dans un fichier. Ainsi, nous pouvons extraire une archive imbriquée dans un flux mémoire.
Remarque : la mémoire virtuelle doit être suffisamment grande pour contenir tout le contenu extrait.
1byte[] b = new byte[8192] ;
2int bytesRead ;
3InputStream entryStream = entry.open() ;
4ByteArrayOutputStream innerCompressed = new ByteArrayOutputStream() ;
5while (0 < (bytesRead = entryStream.read(b, 0, b.length))) {
6 innerCompressed.write(b, 0, bytesRead) ;
7}
Ensuite, le flux innerCompressed contient l’archive interne elle-même. Le Constructeur d’archive permet de décompresser le flux fourni. Nous pouvons donc également l’extraire :
1Archive inner = new Archive(new ByteArrayInputStream(innerCompressed.toByteArray())) ;
Exclusion des entrées
Nous pouvons supprimer une entrée de l’archive zip avec méthode particulière.
1for(ArchiveEntry e : entriesToDelete) {
2 outer.deleteEntry(e) ;
3}
Mettre le tout ensemble
Voici l’algorithme complet.
1try(Archive outer = new Archive("outer.zip")) {
2 ArrayList<ArchiveEntry> entriesToDelete = new ArrayList<ArchiveEntry>() ;
3 ArrayList<String> namesToInsert = new ArrayList<String>() ;
4 ArrayList<InputStream> contentToInsert = new ArrayList<InputStream>() ;
5 for(ArchiveEntry entry : outer.getEntries()) {
6 // Recherche d'une entrée qui est elle-même une archive
7 if(entry.getName().toLowerCase(Locale.ROOT).endsWith(".zip")) {
8 // Conserver la référence à l'entrée afin de la supprimer de l'archive ultérieurement
9 entriesToDelete.add(entry) ;
10
11 //This extracts the entry to a memory stream
12 byte[] b = new byte[8192];
13 int bytesRead;
14 InputStream entryStream = entry.open();
15 ByteArrayOutputStream innerCompressed = new ByteArrayOutputStream();
16 while (0 < (bytesRead = entryStream.read(b, 0, b.length))) {
17 innerCompressed.write(b, 0, bytesRead);
18 }
19
20 // We know that content of the entry is a zip archive, so we may extract
21 try(Archive inner = new Archive(new ByteArrayInputStream(innerCompressed.toByteArray()))) {
22
23 // Loop over entries of inner archive
24 for(ArchiveEntry ie : inner.getEntries()) {
25
26 // Keep the name of inner entry.
27 namesToInsert.add(ie.getName());
28
29 InputStream ieStream = ie.open();
30 ByteArrayOutputStream content = new ByteArrayOutputStream();
31 while (0 < (bytesRead = ieStream.read(b, 0, b.length))) {
32 content.write(b, 0, bytesRead);
33 }
34
35 // Keep the content of inner entry.
36 contentToInsert.add(new ByteArrayInputStream(content.toByteArray()));
37 }
38 }
39 }
40 }
41
42 for(ArchiveEntry e : entriesToDelete) {
43 // Delete all the entries which are archives itself
44 outer.deleteEntry(e);
45 }
46
47 for(int i = 0; i < namesToInsert.size(); i++) {
48 // Adds entries which were entries of inner archives
49 outer.createEntry(namesToInsert.get(i), contentToInsert.get(i));
50 }
51
52 outer.save("flatten.zip");
53} catch (Exception ex) {
54 System.out.println(ex) ;
55}