Zippen en uitpakken in Java

1. Overzicht

In deze korte tutorial bespreken we hoe je een bestand in een archief kunt zippen en hoe je het archief kunt uitpakken - allemaal met behulp van kernbibliotheken die door Java worden geleverd.

Deze kernbibliotheken maken deel uit van het java.util.zip pakket - waar we alle aan zip en unzipping gerelateerde hulpprogramma's kunnen vinden.

2. Zip een bestand

Laten we eerst eens kijken naar een simpele handeling: het zippen van een enkel bestand.

Voor ons voorbeeld hier zullen we een bestand met de naam test1.txt in een gearchiveerde naam gecomprimeerd.zip.

We zullen natuurlijk eerst het bestand vanaf schijf openen - laten we eens kijken:

openbare klasse ZipFile {openbare statische leegte hoofd (String [] args) gooit IOException {String sourceFile = "test1.txt"; FileOutputStream fos = nieuwe FileOutputStream ("gecomprimeerd.zip"); ZipOutputStream zipOut = nieuwe ZipOutputStream (fos); File fileToZip = nieuw bestand (sourceFile); FileInputStream fis = nieuwe FileInputStream (fileToZip); ZipEntry zipEntry = nieuwe ZipEntry (fileToZip.getName ()); zipOut.putNextEntry (zipEntry); byte [] bytes = nieuwe byte [1024]; int lengte; while ((length = fis.read (bytes))> = 0) {zipOut.write (bytes, 0, length); } zipOut.close (); fis.close (); fos.close (); }}

3. Zip meerdere bestanden

Laten we vervolgens kijken hoe u meerdere bestanden in één zipbestand kunt zippen. We zullen comprimeren test1.txt en test2.txt in multiCompressed.zip:

openbare klasse ZipMultipleFiles {openbare statische leegte hoofd (String [] args) gooit IOException {List srcFiles = Arrays.asList ("test1.txt", "test2.txt"); FileOutputStream fos = nieuwe FileOutputStream ("multiCompressed.zip"); ZipOutputStream zipOut = nieuwe ZipOutputStream (fos); voor (String srcFile: srcFiles) {File fileToZip = nieuw bestand (srcFile); FileInputStream fis = nieuwe FileInputStream (fileToZip); ZipEntry zipEntry = nieuwe ZipEntry (fileToZip.getName ()); zipOut.putNextEntry (zipEntry); byte [] bytes = nieuwe byte [1024]; int lengte; while ((length = fis.read (bytes))> = 0) {zipOut.write (bytes, 0, length); } fis.close (); } zipOut.close (); fos.close (); }}

4. Zip een directory

Laten we nu bespreken hoe u een hele directory kunt zippen. We zullen directory zipTest in dirCompressed.zip :

openbare klasse ZipDirectory {openbare statische leegte hoofd (String [] args) gooit IOException {String sourceFile = "zipTest"; FileOutputStream fos = nieuwe FileOutputStream ("dirCompressed.zip"); ZipOutputStream zipOut = nieuwe ZipOutputStream (fos); File fileToZip = nieuw bestand (sourceFile); zipFile (fileToZip, fileToZip.getName (), zipOut); zipOut.close (); fos.close (); } privé statisch ongeldig zipFile (File fileToZip, String fileName, ZipOutputStream zipOut) gooit IOException {if (fileToZip.isHidden ()) {return; } if (fileToZip.isDirectory ()) {if (fileName.endsWith ("/")) {zipOut.putNextEntry (nieuwe ZipEntry (bestandsnaam)); zipOut.closeEntry (); } else {zipOut.putNextEntry (nieuwe ZipEntry (bestandsnaam + "/")); zipOut.closeEntry (); } Bestand [] kinderen = fileToZip.listFiles (); voor (File childFile: children) {zipFile (childFile, fileName + "/" + childFile.getName (), zipOut); } terugkeer; } FileInputStream fis = nieuwe FileInputStream (fileToZip); ZipEntry zipEntry = nieuwe ZipEntry (bestandsnaam); zipOut.putNextEntry (zipEntry); byte [] bytes = nieuwe byte [1024]; int lengte; while ((length = fis.read (bytes))> = 0) {zipOut.write (bytes, 0, length); } fis.close (); }}

Let daar op:

  • Om submappen te zippen, herhalen we ze recursief.
  • Elke keer dat we een directory vinden, voegen we de naam ervan toe aan de nakomelingen ZipEntry naam om de hiërarchie op te slaan.
  • We maken ook een directoryvermelding voor elke lege directory

5. Pak een archief uit

Laten we nu een archief uitpakken en de inhoud ervan uitpakken.

Voor dit voorbeeld zullen we unzippen gecomprimeerd.zip in een nieuwe map met de naam unzipTest.

Laten we eens kijken:

public class UnzipFile {public static void main (String [] args) gooit IOException {String fileZip = "src / main / resources / unzipTest / gecomprimeerd.zip"; Bestand destDir = nieuw bestand ("src / main / resources / unzipTest"); byte [] buffer = nieuwe byte [1024]; ZipInputStream zis = nieuwe ZipInputStream (nieuwe FileInputStream (fileZip)); ZipEntry zipEntry = zis.getNextEntry (); while (zipEntry! = null) {// ...} zis.closeEntry (); zis.close (); }}

Binnen in de terwijl lus, we zullen elk doorlopen ZipEntry en controleer eerst of het een directory is. Als dat het geval is, maken we de map met de mkdirs () methode; anders gaan we door met het maken van het bestand:

while (zipEntry! = null) {File newFile = newFile (destDir, zipEntry); if (zipEntry.isDirectory ()) {if (! newFile.isDirectory () &&! newFile.mkdirs ()) {gooi nieuwe IOException ("Kan map niet maken" + newFile); }} else {// fix voor door Windows gemaakte archieven Bestand ouder = newFile.getParentFile (); if (! parent.isDirectory () &&! parent.mkdirs ()) {throw nieuwe IOException ("Aanmaken map mislukt" + parent); } // schrijf bestandsinhoud FileOutputStream fos = nieuwe FileOutputStream (newFile); int len; while ((len = zis.read (buffer))> 0) {fos.write (buffer, 0, len); } fos.close (); } zipEntry = zis.getNextEntry (); }

Een opmerking hier is dat op de anders branch, controleren we ook eerst of de bovenliggende directory van het bestand bestaat. Dit is nodig voor archieven die zijn gemaakt op Windows, waar de root-mappen geen overeenkomstige vermelding in het zip-bestand hebben.

Een ander belangrijk punt is te zien in de nieuw bestand() methode:

openbaar statisch bestand newFile (bestand bestemmingsmap, zipEntry zipEntry) gooit IOException {bestand destFile = nieuw bestand (bestemmingsmap, zipEntry.getnaam ()); String destDirPath = destinationDir.getCanonicalPath (); String destFilePath = destFile.getCanonicalPath (); if (! destFilePath.startsWith (destDirPath + File.separator)) {throw new IOException ("Entry bevindt zich buiten de doelmap:" + zipEntry.getName ()); } retourneer destFile; }

Deze methode beschermt tegen het schrijven van bestanden naar het bestandssysteem buiten de doelmap. Deze kwetsbaarheid heet Zip Slip en je kunt er hier meer over lezen.

6. Conclusie

Deze tutorial illustreerde hoe we Java-bibliotheken kunnen gebruiken voor het zippen en uitpakken van bestanden.

De implementatie van deze voorbeelden is te vinden op GitHub.