Lynlåsning og udpakning i Java

1. Oversigt

I denne hurtige vejledning diskuterer vi, hvordan du zip en fil i et arkiv, og hvordan du pakke arkivet ud - alt sammen ved hjælp af kernebiblioteker leveret af Java.

Disse kernebiblioteker er en del af java.util.zip pakke - hvor vi kan finde alle relaterede værktøjer til lynlåsning og udpakning.

2. Zip en fil

Lad os først se på en simpel operation - zip en enkelt fil.

For vores eksempel her zip vi en fil med navnet test1.txt ind i et arkiveret navn compressed.zip.

Vi får selvfølgelig først adgang til filen fra disken - lad os se på:

offentlig klasse ZipFile {offentlig statisk ugyldig hoved (String [] args) kaster IOException {String sourceFile = "test1.txt"; FileOutputStream fos = ny FileOutputStream ("compressed.zip"); ZipOutputStream zipOut = ny ZipOutputStream (fos); File fileToZip = ny fil (sourceFile); FileInputStream fis = ny FileInputStream (fileToZip); ZipEntry zipEntry = ny ZipEntry (fileToZip.getName ()); zipOut.putNextEntry (zipEntry); byte [] bytes = ny byte [1024]; int længde; mens ((længde = fis.læs (bytes))> = 0) {zipOut.write (bytes, 0, længde); } zipOut.close (); fis.close (); fos.close (); }}

3. Zip flere filer

Lad os derefter se, hvordan du zip flere filer i en zip-fil. Vi komprimerer test1.txt og test2.txt ind i multiCompressed.zip:

public class ZipMultipleFiles {public static void main (String [] args) throw IOException {List srcFiles = Arrays.asList ("test1.txt", "test2.txt"); FileOutputStream fos = ny FileOutputStream ("multiCompressed.zip"); ZipOutputStream zipOut = ny ZipOutputStream (fos); for (String srcFile: srcFiles) {File fileToZip = ny fil (srcFile); FileInputStream fis = ny FileInputStream (fileToZip); ZipEntry zipEntry = ny ZipEntry (fileToZip.getName ()); zipOut.putNextEntry (zipEntry); byte [] bytes = ny byte [1024]; int længde; mens ((længde = fis.læs (bytes))> = 0) {zipOut.write (bytes, 0, længde); } fis.close (); } zipOut.close (); fos.close (); }}

4. Zip en telefonbog

Lad os nu diskutere, hvordan man zip en hel mappe. Vi katalogiserer zipTest ind i dirCompressed.zip :

offentlig klasse ZipDirectory {public static void main (String [] args) kaster IOException {String sourceFile = "zipTest"; FileOutputStream fos = ny FileOutputStream ("dirCompressed.zip"); ZipOutputStream zipOut = ny ZipOutputStream (fos); File fileToZip = ny fil (sourceFile); zipFile (fileToZip, fileToZip.getName (), zipOut); zipOut.close (); fos.close (); } privat statisk ugyldigt zipFile (File fileToZip, String fileName, ZipOutputStream zipOut) kaster IOException {if (fileToZip.isHidden ()) {return; } hvis (fileToZip.isDirectory ()) {if (fileName.endsWith ("/")) {zipOut.putNextEntry (ny ZipEntry (filnavn)); zipOut.closeEntry (); } andet {zipOut.putNextEntry (nyt ZipEntry (filnavn + "/")); zipOut.closeEntry (); } Fil [] børn = fileToZip.listFiles (); for (File childFile: children) {zipFile (childFile, fileName + "/" + childFile.getName (), zipOut); } Vend tilbage; } FileInputStream fis = ny FileInputStream (fileToZip); ZipEntry zipEntry = ny ZipEntry (filnavn); zipOut.putNextEntry (zipEntry); byte [] bytes = ny byte [1024]; int længde; mens ((længde = fis.læs (bytes))> = 0) {zipOut.write (bytes, 0, længde); } fis.close (); }}

Noter det:

  • For at zip underkataloger gentager vi dem rekursivt.
  • Hver gang vi finder et bibliotek, tilføjer vi dets navn til efterkommerne ZipEntry navn for at gemme hierarkiet.
  • Vi opretter også en mappepost for hver tom mappe

5. Pak et arkiv ud

Lad os nu pakke et arkiv ud og udpakke dets indhold.

I dette eksempel pakker vi ud compressed.zip i en ny mappe med navnet unzipTest.

Lad os kigge på det:

offentlig klasse UnzipFile {public static void main (String [] args) kaster IOException {String fileZip = "src / main / resources / unzipTest / compressed.zip"; Fil destDir = ny fil ("src / main / resources / unzipTest"); byte [] buffer = ny byte [1024]; ZipInputStream zis = ny ZipInputStream (ny FileInputStream (fileZip)); ZipEntry zipEntry = zis.getNextEntry (); mens (zipEntry! = null) {// ...} zis.closeEntry (); zis.close (); }}

Inde i mens løkke, vi gentager gennem hver ZipEntry og kontroller først, om det er et bibliotek. Hvis det er tilfældet, opretter vi biblioteket ved hjælp af mkdirs () metode; Ellers fortsætter vi med at oprette filen:

while (zipEntry! = null) {File newFile = newFile (destDir, zipEntry); if (zipEntry.isDirectory ()) {if (! newFile.isDirectory () &&! newFile.mkdirs ()) {throw new IOException ("Kunne ikke oprette mappe" + newFile); }} andet {// fix til Windows-oprettede arkiver File parent = newFile.getParentFile (); if (! parent.isDirectory () &&! parent.mkdirs ()) {throw new IOException ("Kunne ikke oprette mappe" + forælder); } // skriv filindhold FileOutputStream fos = nyt FileOutputStream (newFile); int len; mens ((len = zis.read (buffer))> 0) {fos.write (buffer, 0, len); } fos.close (); } zipEntry = zis.getNextEntry (); }

En note her er, at på andet gren, kontrollerer vi også først, om filens overordnede bibliotek findes. Dette er nødvendigt for arkiver oprettet på Windows, hvor rodmapperne ikke har en tilsvarende post i zip-filen.

Et andet vigtigt punkt kan ses i newFile () metode:

offentlig statisk fil newFile (File destinationDir, ZipEntry zipEntry) kaster IOException {File destFile = new File (destinationDir, zipEntry.getName ()); Streng destDirPath = destinationDir.getCanonicalPath (); Streng destFilePath = destFile.getCanonicalPath (); hvis (! destFilePath.startsWith (destDirPath + File.separator)) {smid ny IOException ("Entry er uden for mål dir:" + zipEntry.getName ()); } returnere destFile; }

Denne metode beskytter mod at skrive filer til filsystemet uden for målmappen. Denne sårbarhed kaldes Zip Slip, og du kan læse mere om det her.

6. Konklusion

Denne vejledning illustrerede, hvordan vi kan bruge Java-biblioteker til operationer af zip og udpakning af filer.

Implementeringen af ​​disse eksempler findes på GitHub.